Home | History | Annotate | Download | only in translator
      1 //
      2 // Copyright (c) 2002-2014 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 "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
      8 #include "compiler/translator/compilerdebug.h"
      9 
     10 #include <algorithm>
     11 
     12 #include "angle_gl.h"
     13 #include "common/angleutils.h"
     14 
     15 namespace
     16 {
     17 
     18 bool ContainsMatrixNode(const TIntermSequence &sequence)
     19 {
     20     for (size_t ii = 0; ii < sequence.size(); ++ii)
     21     {
     22         TIntermTyped *node = sequence[ii]->getAsTyped();
     23         if (node && node->isMatrix())
     24             return true;
     25     }
     26     return false;
     27 }
     28 
     29 bool ContainsVectorNode(const TIntermSequence &sequence)
     30 {
     31     for (size_t ii = 0; ii < sequence.size(); ++ii)
     32     {
     33         TIntermTyped *node = sequence[ii]->getAsTyped();
     34         if (node && node->isVector())
     35             return true;
     36     }
     37     return false;
     38 }
     39 
     40 TIntermConstantUnion *ConstructIndexNode(int index)
     41 {
     42     ConstantUnion *u = new ConstantUnion[1];
     43     u[0].setIConst(index);
     44 
     45     TType type(EbtInt, EbpUndefined, EvqConst, 1);
     46     TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
     47     return node;
     48 }
     49 
     50 TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
     51 {
     52     TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
     53     binary->setLeft(symbolNode);
     54     TIntermConstantUnion *indexNode = ConstructIndexNode(index);
     55     binary->setRight(indexNode);
     56     return binary;
     57 }
     58 
     59 TIntermBinary *ConstructMatrixIndexBinaryNode(
     60     TIntermSymbol *symbolNode, int colIndex, int rowIndex)
     61 {
     62     TIntermBinary *colVectorNode =
     63         ConstructVectorIndexBinaryNode(symbolNode, colIndex);
     64 
     65     TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
     66     binary->setLeft(colVectorNode);
     67     TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex);
     68     binary->setRight(rowIndexNode);
     69     return binary;
     70 }
     71 
     72 }  // namespace anonymous
     73 
     74 bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node)
     75 {
     76     if (visit == PreVisit)
     77     {
     78         switch (node->getOp())
     79         {
     80           case EOpSequence:
     81             mSequenceStack.push_back(TIntermSequence());
     82             {
     83                 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
     84                      iter != node->getSequence()->end(); ++iter)
     85                 {
     86                     TIntermNode *child = *iter;
     87                     ASSERT(child != NULL);
     88                     child->traverse(this);
     89                     mSequenceStack.back().push_back(child);
     90                 }
     91             }
     92             if (mSequenceStack.back().size() > node->getSequence()->size())
     93             {
     94                 node->getSequence()->clear();
     95                 *(node->getSequence()) = mSequenceStack.back();
     96             }
     97             mSequenceStack.pop_back();
     98             return false;
     99           case EOpConstructVec2:
    100           case EOpConstructVec3:
    101           case EOpConstructVec4:
    102           case EOpConstructBVec2:
    103           case EOpConstructBVec3:
    104           case EOpConstructBVec4:
    105           case EOpConstructIVec2:
    106           case EOpConstructIVec3:
    107           case EOpConstructIVec4:
    108             if (ContainsMatrixNode(*(node->getSequence())))
    109                 scalarizeArgs(node, false, true);
    110             break;
    111           case EOpConstructMat2:
    112           case EOpConstructMat3:
    113           case EOpConstructMat4:
    114             if (ContainsVectorNode(*(node->getSequence())))
    115                 scalarizeArgs(node, true, false);
    116             break;
    117           default:
    118             break;
    119         }
    120     }
    121     return true;
    122 }
    123 
    124 void ScalarizeVecAndMatConstructorArgs::scalarizeArgs(
    125     TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix)
    126 {
    127     ASSERT(aggregate);
    128     int size = 0;
    129     switch (aggregate->getOp())
    130     {
    131       case EOpConstructVec2:
    132       case EOpConstructBVec2:
    133       case EOpConstructIVec2:
    134         size = 2;
    135         break;
    136       case EOpConstructVec3:
    137       case EOpConstructBVec3:
    138       case EOpConstructIVec3:
    139         size = 3;
    140         break;
    141       case EOpConstructVec4:
    142       case EOpConstructBVec4:
    143       case EOpConstructIVec4:
    144       case EOpConstructMat2:
    145         size = 4;
    146         break;
    147       case EOpConstructMat3:
    148         size = 9;
    149         break;
    150       case EOpConstructMat4:
    151         size = 16;
    152         break;
    153       default:
    154         break;
    155     }
    156     TIntermSequence *sequence = aggregate->getSequence();
    157     TIntermSequence original(*sequence);
    158     sequence->clear();
    159     for (size_t ii = 0; ii < original.size(); ++ii)
    160     {
    161         ASSERT(size > 0);
    162         TIntermTyped *node = original[ii]->getAsTyped();
    163         ASSERT(node);
    164         TString varName = createTempVariable(node);
    165         if (node->isScalar())
    166         {
    167             TIntermSymbol *symbolNode =
    168                 new TIntermSymbol(-1, varName, node->getType());
    169             sequence->push_back(symbolNode);
    170             size--;
    171         }
    172         else if (node->isVector())
    173         {
    174             if (scalarizeVector)
    175             {
    176                 int repeat = std::min(size, node->getNominalSize());
    177                 size -= repeat;
    178                 for (int index = 0; index < repeat; ++index)
    179                 {
    180                     TIntermSymbol *symbolNode =
    181                         new TIntermSymbol(-1, varName, node->getType());
    182                     TIntermBinary *newNode = ConstructVectorIndexBinaryNode(
    183                         symbolNode, index);
    184                     sequence->push_back(newNode);
    185                 }
    186             }
    187             else
    188             {
    189                 TIntermSymbol *symbolNode =
    190                     new TIntermSymbol(-1, varName, node->getType());
    191                 sequence->push_back(symbolNode);
    192                 size -= node->getNominalSize();
    193             }
    194         }
    195         else
    196         {
    197             ASSERT(node->isMatrix());
    198             if (scalarizeMatrix)
    199             {
    200                 int colIndex = 0, rowIndex = 0;
    201                 int repeat = std::min(size, node->getCols() * node->getRows());
    202                 size -= repeat;
    203                 while (repeat > 0)
    204                 {
    205                     TIntermSymbol *symbolNode =
    206                         new TIntermSymbol(-1, varName, node->getType());
    207                     TIntermBinary *newNode = ConstructMatrixIndexBinaryNode(
    208                         symbolNode, colIndex, rowIndex);
    209                     sequence->push_back(newNode);
    210                     rowIndex++;
    211                     if (rowIndex >= node->getRows())
    212                     {
    213                         rowIndex = 0;
    214                         colIndex++;
    215                     }
    216                     repeat--;
    217                 }
    218             }
    219             else
    220             {
    221                 TIntermSymbol *symbolNode =
    222                     new TIntermSymbol(-1, varName, node->getType());
    223                 sequence->push_back(symbolNode);
    224                 size -= node->getCols() * node->getRows();
    225             }
    226         }
    227     }
    228 }
    229 
    230 TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original)
    231 {
    232     TString tempVarName = "_webgl_tmp_";
    233     if (original->isScalar())
    234     {
    235         tempVarName += "scalar_";
    236     }
    237     else if (original->isVector())
    238     {
    239         tempVarName += "vec_";
    240     }
    241     else
    242     {
    243         ASSERT(original->isMatrix());
    244         tempVarName += "mat_";
    245     }
    246     tempVarName += Str(mTempVarCount).c_str();
    247     mTempVarCount++;
    248 
    249     ASSERT(original);
    250     TType type = original->getType();
    251     type.setQualifier(EvqTemporary);
    252 
    253     if (mShaderType == GL_FRAGMENT_SHADER &&
    254         type.getBasicType() == EbtFloat &&
    255         type.getPrecision() == EbpUndefined)
    256     {
    257         // We use the highest available precision for the temporary variable
    258         // to avoid computing the actual precision using the rules defined
    259         // in GLSL ES 1.0 Section 4.5.2.
    260         type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
    261     }
    262 
    263     TIntermBinary *init = new TIntermBinary(EOpInitialize);
    264     TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
    265     init->setLeft(symbolNode);
    266     init->setRight(original);
    267     init->setType(type);
    268 
    269     TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
    270     decl->getSequence()->push_back(init);
    271 
    272     ASSERT(mSequenceStack.size() > 0);
    273     TIntermSequence &sequence = mSequenceStack.back();
    274     sequence.push_back(decl);
    275 
    276     return tempVarName;
    277 }
    278