Home | History | Annotate | Download | only in translator
      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 }
    439