Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / VariableInfo.cpp
1 //
2 // Copyright (c) 2002-2013 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 "angle_gl.h"
8 #include "compiler/translator/VariableInfo.h"
9 #include "compiler/translator/util.h"
10 #include "common/utilities.h"
11
12 template <typename VarT>
13 static void ExpandUserDefinedVariable(const VarT &variable,
14                                       const std::string &name,
15                                       const std::string &mappedName,
16                                       bool markStaticUse,
17                                       std::vector<VarT> *expanded);
18
19 // Returns info for an attribute, uniform, or varying.
20 template <typename VarT>
21 static void ExpandVariable(const VarT &variable,
22                            const std::string &name,
23                            const std::string &mappedName,
24                            bool markStaticUse,
25                            std::vector<VarT> *expanded)
26 {
27     if (variable.isStruct())
28     {
29         if (variable.isArray())
30         {
31             for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
32             {
33                 std::string lname = name + ArrayString(elementIndex);
34                 std::string lmappedName = mappedName + ArrayString(elementIndex);
35                 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
36             }
37         }
38         else
39         {
40             ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
41         }
42     }
43     else
44     {
45         VarT expandedVar = variable;
46
47         expandedVar.name = name;
48         expandedVar.mappedName = mappedName;
49
50         // Mark all expanded fields as used if the parent is used
51         if (markStaticUse)
52         {
53             expandedVar.staticUse = true;
54         }
55
56         if (expandedVar.isArray())
57         {
58             expandedVar.name += "[0]";
59             expandedVar.mappedName += "[0]";
60         }
61
62         expanded->push_back(expandedVar);
63     }
64 }
65
66 template <class VarT>
67 static void ExpandUserDefinedVariable(const VarT &variable,
68                                       const std::string &name,
69                                       const std::string &mappedName,
70                                       bool markStaticUse,
71                                       std::vector<VarT> *expanded)
72 {
73     ASSERT(variable.isStruct());
74
75     const std::vector<VarT> &fields = variable.fields;
76
77     for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
78     {
79         const VarT &field = fields[fieldIndex];
80         ExpandVariable(field,
81                        name + "." + field.name,
82                        mappedName + "." + field.mappedName,
83                        markStaticUse,
84                        expanded);
85     }
86 }
87
88 template <class VarT>
89 static VarT *FindVariable(const TString &name,
90                           std::vector<VarT> *infoList)
91 {
92     // TODO(zmo): optimize this function.
93     for (size_t ii = 0; ii < infoList->size(); ++ii)
94     {
95         if ((*infoList)[ii].name.c_str() == name)
96             return &((*infoList)[ii]);
97     }
98
99     return NULL;
100 }
101
102 CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
103                                    std::vector<sh::Attribute> *outputVariables,
104                                    std::vector<sh::Uniform> *uniforms,
105                                    std::vector<sh::Varying> *varyings,
106                                    std::vector<sh::InterfaceBlock> *interfaceBlocks,
107                                    ShHashFunction64 hashFunction)
108     : mAttribs(attribs),
109       mOutputVariables(outputVariables),
110       mUniforms(uniforms),
111       mVaryings(varyings),
112       mInterfaceBlocks(interfaceBlocks),
113       mPointCoordAdded(false),
114       mFrontFacingAdded(false),
115       mFragCoordAdded(false),
116       mHashFunction(hashFunction)
117 {
118 }
119
120 // We want to check whether a uniform/varying is statically used
121 // because we only count the used ones in packing computing.
122 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
123 // toward varying counting if they are statically used in a fragment
124 // shader.
125 void CollectVariables::visitSymbol(TIntermSymbol *symbol)
126 {
127     ASSERT(symbol != NULL);
128     sh::ShaderVariable *var = NULL;
129     const TString &symbolName = symbol->getSymbol();
130
131     if (sh::IsVarying(symbol->getQualifier()))
132     {
133         var = FindVariable(symbolName, mVaryings);
134     }
135     else if (symbol->getType() != EbtInterfaceBlock)
136     {
137         switch (symbol->getQualifier())
138         {
139           case EvqAttribute:
140           case EvqVertexIn:
141             var = FindVariable(symbolName, mAttribs);
142             break;
143           case EvqFragmentOut:
144             var = FindVariable(symbolName, mOutputVariables);
145             break;
146           case EvqUniform:
147             {
148                 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
149                 if (interfaceBlock)
150                 {
151                     sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
152                     ASSERT(namedBlock);
153                     var = FindVariable(symbolName, &namedBlock->fields);
154
155                     // Set static use on the parent interface block here
156                     namedBlock->staticUse = true;
157                 }
158                 else
159                 {
160                     var = FindVariable(symbolName, mUniforms);
161                 }
162
163                 // It's an internal error to reference an undefined user uniform
164                 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
165             }
166             break;
167           case EvqFragCoord:
168             if (!mFragCoordAdded)
169             {
170                 sh::Varying info;
171                 info.name = "gl_FragCoord";
172                 info.mappedName = "gl_FragCoord";
173                 info.type = GL_FLOAT_VEC4;
174                 info.arraySize = 0;
175                 info.precision = GL_MEDIUM_FLOAT;  // Use mediump as it doesn't really matter.
176                 info.staticUse = true;
177                 mVaryings->push_back(info);
178                 mFragCoordAdded = true;
179             }
180             return;
181           case EvqFrontFacing:
182             if (!mFrontFacingAdded)
183             {
184                 sh::Varying info;
185                 info.name = "gl_FrontFacing";
186                 info.mappedName = "gl_FrontFacing";
187                 info.type = GL_BOOL;
188                 info.arraySize = 0;
189                 info.precision = GL_NONE;
190                 info.staticUse = true;
191                 mVaryings->push_back(info);
192                 mFrontFacingAdded = true;
193             }
194             return;
195           case EvqPointCoord:
196             if (!mPointCoordAdded)
197             {
198                 sh::Varying info;
199                 info.name = "gl_PointCoord";
200                 info.mappedName = "gl_PointCoord";
201                 info.type = GL_FLOAT_VEC2;
202                 info.arraySize = 0;
203                 info.precision = GL_MEDIUM_FLOAT;  // Use mediump as it doesn't really matter.
204                 info.staticUse = true;
205                 mVaryings->push_back(info);
206                 mPointCoordAdded = true;
207             }
208             return;
209           default:
210             break;
211         }
212     }
213     if (var)
214     {
215         var->staticUse = true;
216     }
217 }
218
219 template <typename VarT>
220 class NameHashingTraverser : public sh::GetVariableTraverser<VarT>
221 {
222   public:
223     NameHashingTraverser(std::vector<VarT> *output, ShHashFunction64 hashFunction)
224         : sh::GetVariableTraverser<VarT>(output),
225           mHashFunction(hashFunction)
226     {}
227
228   private:
229     void visitVariable(VarT *variable)
230     {
231         TString stringName = TString(variable->name.c_str());
232         variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
233     }
234
235     ShHashFunction64 mHashFunction;
236 };
237
238 // Attributes, which cannot have struct fields, are a special case
239 template <>
240 void CollectVariables::visitVariable(const TIntermSymbol *variable,
241                                      std::vector<sh::Attribute> *infoList) const
242 {
243     ASSERT(variable);
244     const TType &type = variable->getType();
245     ASSERT(!type.getStruct());
246
247     sh::Attribute attribute;
248
249     attribute.type = sh::GLVariableType(type);
250     attribute.precision = sh::GLVariablePrecision(type);
251     attribute.name = variable->getSymbol().c_str();
252     attribute.arraySize = static_cast<unsigned int>(type.getArraySize());
253     attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
254     attribute.location = variable->getType().getLayoutQualifier().location;
255
256     infoList->push_back(attribute);
257 }
258
259 template <>
260 void CollectVariables::visitVariable(const TIntermSymbol *variable,
261                                      std::vector<sh::InterfaceBlock> *infoList) const
262 {
263     sh::InterfaceBlock interfaceBlock;
264     const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
265
266     bool isRowMajor = (blockType->matrixPacking() == EmpRowMajor);
267
268     interfaceBlock.name = blockType->name().c_str();
269     interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
270     interfaceBlock.arraySize = variable->getArraySize();
271     interfaceBlock.isRowMajorLayout = isRowMajor;
272     interfaceBlock.layout = sh::GetBlockLayoutType(blockType->blockStorage());
273
274     ASSERT(blockType);
275     const TFieldList &blockFields = blockType->fields();
276
277     for (size_t fieldIndex = 0; fieldIndex < blockFields.size(); fieldIndex++)
278     {
279         const TField *field = blockFields[fieldIndex];
280         ASSERT(field);
281
282         sh::GetInterfaceBlockFieldTraverser traverser(&interfaceBlock.fields, isRowMajor);
283         traverser.traverse(*field->type(), field->name());
284     }
285
286     infoList->push_back(interfaceBlock);
287 }
288
289 template <typename VarT>
290 void CollectVariables::visitVariable(const TIntermSymbol *variable,
291                                      std::vector<VarT> *infoList) const
292 {
293     NameHashingTraverser<VarT> traverser(infoList, mHashFunction);
294     traverser.traverse(variable->getType(), variable->getSymbol());
295 }
296
297 template <typename VarT>
298 void CollectVariables::visitInfoList(const TIntermSequence &sequence,
299                                      std::vector<VarT> *infoList) const
300 {
301     for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
302     {
303         const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
304         // The only case in which the sequence will not contain a
305         // TIntermSymbol node is initialization. It will contain a
306         // TInterBinary node in that case. Since attributes, uniforms,
307         // and varyings cannot be initialized in a shader, we must have
308         // only TIntermSymbol nodes in the sequence.
309         ASSERT(variable != NULL);
310         visitVariable(variable, infoList);
311     }
312 }
313
314 bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
315 {
316     bool visitChildren = true;
317
318     switch (node->getOp())
319     {
320       case EOpDeclaration:
321         {
322             const TIntermSequence &sequence = *(node->getSequence());
323             ASSERT(!sequence.empty());
324
325             const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
326             TQualifier qualifier = typedNode.getQualifier();
327
328             if (typedNode.getBasicType() == EbtInterfaceBlock)
329             {
330                 visitInfoList(sequence, mInterfaceBlocks);
331             }
332             else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
333                      qualifier == EvqFragmentOut || qualifier == EvqUniform ||
334                      sh::IsVarying(qualifier))
335             {
336                 switch (qualifier)
337                 {
338                   case EvqAttribute:
339                   case EvqVertexIn:
340                     visitInfoList(sequence, mAttribs);
341                     break;
342                   case EvqFragmentOut:
343                     visitInfoList(sequence, mOutputVariables);
344                     break;
345                   case EvqUniform:
346                     visitInfoList(sequence, mUniforms);
347                     break;
348                   default:
349                     // do not traverse invariant declarations such as
350                     //  "invariant gl_Position;"
351                     if (typedNode.getBasicType() != EbtInvariant)
352                     {
353                         visitInfoList(sequence, mVaryings);
354                     }
355                     break;
356                 }
357
358                 visitChildren = false;
359             }
360             break;
361         }
362       default: break;
363     }
364
365     return visitChildren;
366 }
367
368 template <typename VarT>
369 void ExpandVariables(const std::vector<VarT> &compact, std::vector<VarT> *expanded)
370 {
371     for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
372     {
373         const VarT &variable = compact[variableIndex];
374         ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
375     }
376 }
377
378 template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::Uniform> *);
379 template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::Varying> *);