Edit

kc3-lang/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp

Branch :

  • Show log

    Commit

  • Author : Alexis Hetu
    Date : 2015-06-16 16:55:52
    Hash : 07e57df7
    Message : Added non square matrix construction Added new construction operations for non square matrices, along with the required changes to the related translation functions. Change-Id: I04ae7d4b2d1bb363b35d088cea45c0e7c4bc8a13 Reviewed-on: https://chromium-review.googlesource.com/277729 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org> Tested-by: Geoff Lang <geofflang@chromium.org>

  • src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
  • //
    // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "common/debug.h"
    #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
    
    #include <algorithm>
    
    #include "angle_gl.h"
    #include "common/angleutils.h"
    
    namespace
    {
    
    bool ContainsMatrixNode(const TIntermSequence &sequence)
    {
        for (size_t ii = 0; ii < sequence.size(); ++ii)
        {
            TIntermTyped *node = sequence[ii]->getAsTyped();
            if (node && node->isMatrix())
                return true;
        }
        return false;
    }
    
    bool ContainsVectorNode(const TIntermSequence &sequence)
    {
        for (size_t ii = 0; ii < sequence.size(); ++ii)
        {
            TIntermTyped *node = sequence[ii]->getAsTyped();
            if (node && node->isVector())
                return true;
        }
        return false;
    }
    
    TIntermConstantUnion *ConstructIndexNode(int index)
    {
        TConstantUnion *u = new TConstantUnion[1];
        u[0].setIConst(index);
    
        TType type(EbtInt, EbpUndefined, EvqConst, 1);
        TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
        return node;
    }
    
    TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
    {
        TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
        binary->setLeft(symbolNode);
        TIntermConstantUnion *indexNode = ConstructIndexNode(index);
        binary->setRight(indexNode);
        return binary;
    }
    
    TIntermBinary *ConstructMatrixIndexBinaryNode(
        TIntermSymbol *symbolNode, int colIndex, int rowIndex)
    {
        TIntermBinary *colVectorNode =
            ConstructVectorIndexBinaryNode(symbolNode, colIndex);
    
        TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
        binary->setLeft(colVectorNode);
        TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex);
        binary->setRight(rowIndexNode);
        return binary;
    }
    
    }  // namespace anonymous
    
    bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node)
    {
        if (visit == PreVisit)
        {
            switch (node->getOp())
            {
              case EOpSequence:
                mSequenceStack.push_back(TIntermSequence());
                {
                    for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
                         iter != node->getSequence()->end(); ++iter)
                    {
                        TIntermNode *child = *iter;
                        ASSERT(child != NULL);
                        child->traverse(this);
                        mSequenceStack.back().push_back(child);
                    }
                }
                if (mSequenceStack.back().size() > node->getSequence()->size())
                {
                    node->getSequence()->clear();
                    *(node->getSequence()) = mSequenceStack.back();
                }
                mSequenceStack.pop_back();
                return false;
              case EOpConstructVec2:
              case EOpConstructVec3:
              case EOpConstructVec4:
              case EOpConstructBVec2:
              case EOpConstructBVec3:
              case EOpConstructBVec4:
              case EOpConstructIVec2:
              case EOpConstructIVec3:
              case EOpConstructIVec4:
                if (ContainsMatrixNode(*(node->getSequence())))
                    scalarizeArgs(node, false, true);
                break;
              case EOpConstructMat2:
              case EOpConstructMat2x3:
              case EOpConstructMat2x4:
              case EOpConstructMat3x2:
              case EOpConstructMat3:
              case EOpConstructMat3x4:
              case EOpConstructMat4x2:
              case EOpConstructMat4x3:
              case EOpConstructMat4:
                if (ContainsVectorNode(*(node->getSequence())))
                    scalarizeArgs(node, true, false);
                break;
              default:
                break;
            }
        }
        return true;
    }
    
    void ScalarizeVecAndMatConstructorArgs::scalarizeArgs(
        TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix)
    {
        ASSERT(aggregate);
        int size = 0;
        switch (aggregate->getOp())
        {
          case EOpConstructVec2:
          case EOpConstructBVec2:
          case EOpConstructIVec2:
            size = 2;
            break;
          case EOpConstructVec3:
          case EOpConstructBVec3:
          case EOpConstructIVec3:
            size = 3;
            break;
          case EOpConstructVec4:
          case EOpConstructBVec4:
          case EOpConstructIVec4:
          case EOpConstructMat2:
            size = 4;
            break;
          case EOpConstructMat2x3:
          case EOpConstructMat3x2:
            size = 6;
            break;
          case EOpConstructMat2x4:
          case EOpConstructMat4x2:
            size = 8;
            break;
          case EOpConstructMat3:
            size = 9;
            break;
          case EOpConstructMat3x4:
          case EOpConstructMat4x3:
            size = 12;
            break;
          case EOpConstructMat4:
            size = 16;
            break;
          default:
            break;
        }
        TIntermSequence *sequence = aggregate->getSequence();
        TIntermSequence original(*sequence);
        sequence->clear();
        for (size_t ii = 0; ii < original.size(); ++ii)
        {
            ASSERT(size > 0);
            TIntermTyped *node = original[ii]->getAsTyped();
            ASSERT(node);
            TString varName = createTempVariable(node);
            if (node->isScalar())
            {
                TIntermSymbol *symbolNode =
                    new TIntermSymbol(-1, varName, node->getType());
                sequence->push_back(symbolNode);
                size--;
            }
            else if (node->isVector())
            {
                if (scalarizeVector)
                {
                    int repeat = std::min(size, node->getNominalSize());
                    size -= repeat;
                    for (int index = 0; index < repeat; ++index)
                    {
                        TIntermSymbol *symbolNode =
                            new TIntermSymbol(-1, varName, node->getType());
                        TIntermBinary *newNode = ConstructVectorIndexBinaryNode(
                            symbolNode, index);
                        sequence->push_back(newNode);
                    }
                }
                else
                {
                    TIntermSymbol *symbolNode =
                        new TIntermSymbol(-1, varName, node->getType());
                    sequence->push_back(symbolNode);
                    size -= node->getNominalSize();
                }
            }
            else
            {
                ASSERT(node->isMatrix());
                if (scalarizeMatrix)
                {
                    int colIndex = 0, rowIndex = 0;
                    int repeat = std::min(size, node->getCols() * node->getRows());
                    size -= repeat;
                    while (repeat > 0)
                    {
                        TIntermSymbol *symbolNode =
                            new TIntermSymbol(-1, varName, node->getType());
                        TIntermBinary *newNode = ConstructMatrixIndexBinaryNode(
                            symbolNode, colIndex, rowIndex);
                        sequence->push_back(newNode);
                        rowIndex++;
                        if (rowIndex >= node->getRows())
                        {
                            rowIndex = 0;
                            colIndex++;
                        }
                        repeat--;
                    }
                }
                else
                {
                    TIntermSymbol *symbolNode =
                        new TIntermSymbol(-1, varName, node->getType());
                    sequence->push_back(symbolNode);
                    size -= node->getCols() * node->getRows();
                }
            }
        }
    }
    
    TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original)
    {
        TString tempVarName = "_webgl_tmp_";
        if (original->isScalar())
        {
            tempVarName += "scalar_";
        }
        else if (original->isVector())
        {
            tempVarName += "vec_";
        }
        else
        {
            ASSERT(original->isMatrix());
            tempVarName += "mat_";
        }
        tempVarName += Str(mTempVarCount).c_str();
        mTempVarCount++;
    
        ASSERT(original);
        TType type = original->getType();
        type.setQualifier(EvqTemporary);
    
        if (mShaderType == GL_FRAGMENT_SHADER &&
            type.getBasicType() == EbtFloat &&
            type.getPrecision() == EbpUndefined)
        {
            // We use the highest available precision for the temporary variable
            // to avoid computing the actual precision using the rules defined
            // in GLSL ES 1.0 Section 4.5.2.
            type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium);
        }
    
        TIntermBinary *init = new TIntermBinary(EOpInitialize);
        TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type);
        init->setLeft(symbolNode);
        init->setRight(original);
        init->setType(type);
    
        TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
        decl->getSequence()->push_back(init);
    
        ASSERT(mSequenceStack.size() > 0);
        TIntermSequence &sequence = mSequenceStack.back();
        sequence.push_back(decl);
    
        return tempVarName;
    }