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