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