• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 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 // EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin
7 // to a uniform int
8 //
9 // EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin
10 // to a uniform int
11 //
12 // EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin
13 // to a uniform int
14 //
15 
16 #include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h"
17 
18 #include "angle_gl.h"
19 #include "compiler/translator/StaticType.h"
20 #include "compiler/translator/Symbol.h"
21 #include "compiler/translator/SymbolTable.h"
22 #include "compiler/translator/tree_util/BuiltIn.h"
23 #include "compiler/translator/tree_util/IntermTraverse.h"
24 #include "compiler/translator/tree_util/ReplaceVariable.h"
25 #include "compiler/translator/util.h"
26 
27 namespace sh
28 {
29 
30 namespace
31 {
32 
33 constexpr const ImmutableString kEmulatedGLDrawIDName("angle_DrawID");
34 
35 class FindGLDrawIDTraverser : public TIntermTraverser
36 {
37   public:
FindGLDrawIDTraverser()38     FindGLDrawIDTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
39 
getGLDrawIDBuiltinVariable()40     const TVariable *getGLDrawIDBuiltinVariable() { return mVariable; }
41 
42   protected:
visitSymbol(TIntermSymbol * node)43     void visitSymbol(TIntermSymbol *node) override
44     {
45         if (&node->variable() == BuiltInVariable::gl_DrawID())
46         {
47             mVariable = &node->variable();
48         }
49     }
50 
51   private:
52     const TVariable *mVariable;
53 };
54 
55 class AddBaseVertexToGLVertexIDTraverser : public TIntermTraverser
56 {
57   public:
AddBaseVertexToGLVertexIDTraverser()58     AddBaseVertexToGLVertexIDTraverser() : TIntermTraverser(true, false, false) {}
59 
60   protected:
visitSymbol(TIntermSymbol * node)61     void visitSymbol(TIntermSymbol *node) override
62     {
63         if (&node->variable() == BuiltInVariable::gl_VertexID())
64         {
65 
66             TIntermSymbol *baseVertexRef = new TIntermSymbol(BuiltInVariable::gl_BaseVertex());
67 
68             TIntermBinary *addBaseVertex = new TIntermBinary(EOpAdd, node, baseVertexRef);
69             queueReplacement(addBaseVertex, OriginalNode::BECOMES_CHILD);
70         }
71     }
72 };
73 
74 constexpr const ImmutableString kEmulatedGLBaseVertexName("angle_BaseVertex");
75 
76 class FindGLBaseVertexTraverser : public TIntermTraverser
77 {
78   public:
FindGLBaseVertexTraverser()79     FindGLBaseVertexTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
80 
getGLBaseVertexBuiltinVariable()81     const TVariable *getGLBaseVertexBuiltinVariable() { return mVariable; }
82 
83   protected:
visitSymbol(TIntermSymbol * node)84     void visitSymbol(TIntermSymbol *node) override
85     {
86         if (&node->variable() == BuiltInVariable::gl_BaseVertex())
87         {
88             mVariable = &node->variable();
89         }
90     }
91 
92   private:
93     const TVariable *mVariable;
94 };
95 
96 constexpr const ImmutableString kEmulatedGLBaseInstanceName("angle_BaseInstance");
97 
98 class FindGLBaseInstanceTraverser : public TIntermTraverser
99 {
100   public:
FindGLBaseInstanceTraverser()101     FindGLBaseInstanceTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {}
102 
getGLBaseInstanceBuiltinVariable()103     const TVariable *getGLBaseInstanceBuiltinVariable() { return mVariable; }
104 
105   protected:
visitSymbol(TIntermSymbol * node)106     void visitSymbol(TIntermSymbol *node) override
107     {
108         if (&node->variable() == BuiltInVariable::gl_BaseInstance())
109         {
110             mVariable = &node->variable();
111         }
112     }
113 
114   private:
115     const TVariable *mVariable;
116 };
117 
118 }  // namespace
119 
EmulateGLDrawID(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,std::vector<sh::ShaderVariable> * uniforms,bool shouldCollect)120 bool EmulateGLDrawID(TCompiler *compiler,
121                      TIntermBlock *root,
122                      TSymbolTable *symbolTable,
123                      std::vector<sh::ShaderVariable> *uniforms,
124                      bool shouldCollect)
125 {
126     FindGLDrawIDTraverser traverser;
127     root->traverse(&traverser);
128     const TVariable *builtInVariable = traverser.getGLDrawIDBuiltinVariable();
129     if (builtInVariable)
130     {
131         const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
132         const TVariable *drawID =
133             new TVariable(symbolTable, kEmulatedGLDrawIDName, type, SymbolType::AngleInternal);
134         const TIntermSymbol *drawIDSymbol = new TIntermSymbol(drawID);
135 
136         // AngleInternal variables don't get collected
137         if (shouldCollect)
138         {
139             ShaderVariable uniform;
140             uniform.name       = kEmulatedGLDrawIDName.data();
141             uniform.mappedName = kEmulatedGLDrawIDName.data();
142             uniform.type       = GLVariableType(*type);
143             uniform.precision  = GLVariablePrecision(*type);
144             uniform.staticUse  = symbolTable->isStaticallyUsed(*builtInVariable);
145             uniform.active     = true;
146             uniform.binding    = type->getLayoutQualifier().binding;
147             uniform.location   = type->getLayoutQualifier().location;
148             uniform.offset     = type->getLayoutQualifier().offset;
149             uniform.readonly   = type->getMemoryQualifier().readonly;
150             uniform.writeonly  = type->getMemoryQualifier().writeonly;
151             uniforms->push_back(uniform);
152         }
153 
154         DeclareGlobalVariable(root, drawID);
155         if (!ReplaceVariableWithTyped(compiler, root, builtInVariable, drawIDSymbol))
156         {
157             return false;
158         }
159     }
160 
161     return true;
162 }
163 
EmulateGLBaseVertexBaseInstance(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,std::vector<sh::ShaderVariable> * uniforms,bool shouldCollect,bool addBaseVertexToVertexID)164 bool EmulateGLBaseVertexBaseInstance(TCompiler *compiler,
165                                      TIntermBlock *root,
166                                      TSymbolTable *symbolTable,
167                                      std::vector<sh::ShaderVariable> *uniforms,
168                                      bool shouldCollect,
169                                      bool addBaseVertexToVertexID)
170 {
171     bool addBaseVertex = false, addBaseInstance = false;
172     ShaderVariable uniformBaseVertex, uniformBaseInstance;
173 
174     if (addBaseVertexToVertexID)
175     {
176         // This is a workaround for Mac AMD GPU
177         // Replace gl_VertexID with (gl_VertexID + gl_BaseVertex)
178         AddBaseVertexToGLVertexIDTraverser traverserVertexID;
179         root->traverse(&traverserVertexID);
180         if (!traverserVertexID.updateTree(compiler, root))
181         {
182             return false;
183         }
184     }
185 
186     FindGLBaseVertexTraverser traverserBaseVertex;
187     root->traverse(&traverserBaseVertex);
188     const TVariable *builtInVariableBaseVertex =
189         traverserBaseVertex.getGLBaseVertexBuiltinVariable();
190 
191     if (builtInVariableBaseVertex)
192     {
193         const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
194         const TVariable *baseVertex =
195             new TVariable(symbolTable, kEmulatedGLBaseVertexName, type, SymbolType::AngleInternal);
196         const TIntermSymbol *baseVertexSymbol = new TIntermSymbol(baseVertex);
197 
198         // AngleInternal variables don't get collected
199         if (shouldCollect)
200         {
201             uniformBaseVertex.name       = kEmulatedGLBaseVertexName.data();
202             uniformBaseVertex.mappedName = kEmulatedGLBaseVertexName.data();
203             uniformBaseVertex.type       = GLVariableType(*type);
204             uniformBaseVertex.precision  = GLVariablePrecision(*type);
205             uniformBaseVertex.staticUse = symbolTable->isStaticallyUsed(*builtInVariableBaseVertex);
206             uniformBaseVertex.active    = true;
207             uniformBaseVertex.binding   = type->getLayoutQualifier().binding;
208             uniformBaseVertex.location  = type->getLayoutQualifier().location;
209             uniformBaseVertex.offset    = type->getLayoutQualifier().offset;
210             uniformBaseVertex.readonly  = type->getMemoryQualifier().readonly;
211             uniformBaseVertex.writeonly = type->getMemoryQualifier().writeonly;
212             addBaseVertex               = true;
213         }
214 
215         DeclareGlobalVariable(root, baseVertex);
216         if (!ReplaceVariableWithTyped(compiler, root, builtInVariableBaseVertex, baseVertexSymbol))
217         {
218             return false;
219         }
220     }
221 
222     FindGLBaseInstanceTraverser traverserInstance;
223     root->traverse(&traverserInstance);
224     const TVariable *builtInVariableBaseInstance =
225         traverserInstance.getGLBaseInstanceBuiltinVariable();
226 
227     if (builtInVariableBaseInstance)
228     {
229         const TType *type             = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
230         const TVariable *baseInstance = new TVariable(symbolTable, kEmulatedGLBaseInstanceName,
231                                                       type, SymbolType::AngleInternal);
232         const TIntermSymbol *baseInstanceSymbol = new TIntermSymbol(baseInstance);
233 
234         // AngleInternal variables don't get collected
235         if (shouldCollect)
236         {
237             uniformBaseInstance.name       = kEmulatedGLBaseInstanceName.data();
238             uniformBaseInstance.mappedName = kEmulatedGLBaseInstanceName.data();
239             uniformBaseInstance.type       = GLVariableType(*type);
240             uniformBaseInstance.precision  = GLVariablePrecision(*type);
241             uniformBaseInstance.staticUse =
242                 symbolTable->isStaticallyUsed(*builtInVariableBaseInstance);
243             uniformBaseInstance.active    = true;
244             uniformBaseInstance.binding   = type->getLayoutQualifier().binding;
245             uniformBaseInstance.location  = type->getLayoutQualifier().location;
246             uniformBaseInstance.offset    = type->getLayoutQualifier().offset;
247             uniformBaseInstance.readonly  = type->getMemoryQualifier().readonly;
248             uniformBaseInstance.writeonly = type->getMemoryQualifier().writeonly;
249             addBaseInstance               = true;
250         }
251 
252         DeclareGlobalVariable(root, baseInstance);
253         if (!ReplaceVariableWithTyped(compiler, root, builtInVariableBaseInstance,
254                                       baseInstanceSymbol))
255         {
256             return false;
257         }
258     }
259 
260     // Make sure the order in uniforms is the same as the traverse order
261     if (addBaseInstance)
262     {
263         uniforms->push_back(uniformBaseInstance);
264     }
265     if (addBaseVertex)
266     {
267         uniforms->push_back(uniformBaseVertex);
268     }
269 
270     return true;
271 }
272 
273 }  // namespace sh
274