Edit

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

Branch :

  • Show log

    Commit

  • Author : Stuart Morgan
    Date : 2019-08-14 12:25:12
    Hash : 9d737966
    Message : Standardize copyright notices to project style For all "ANGLE Project" copyrights, standardize to the format specified by the style guide. Changes: - "Copyright (c)" and "Copyright(c)" changed to just "Copyright". - Removed the second half of date ranges ("Y1Y1-Y2Y2"->"Y1Y1"). - Fixed a small number of files that had no copyright date using the initial commit year from the version control history. - Fixed one instance of copyright being "The ANGLE Project" rather than "The ANGLE Project Authors" These changes are applied both to the copyright of source file, and where applicable to copyright statements that are generated by templates. BUG=angleproject:3811 Change-Id: I973dd65e4ef9deeba232d5be74c768256a0eb2e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1754397 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/blocklayout.cpp
  • //
    // Copyright 2013 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.
    //
    // blocklayout.cpp:
    //   Implementation for block layout classes and methods.
    //
    
    #include "compiler/translator/blocklayout.h"
    
    #include "common/mathutil.h"
    #include "common/utilities.h"
    #include "compiler/translator/Common.h"
    
    namespace sh
    {
    
    namespace
    {
    class BlockLayoutMapVisitor : public BlockEncoderVisitor
    {
      public:
        BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut,
                              const std::string &instanceName,
                              BlockLayoutEncoder *encoder)
            : BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut)
        {}
    
        void encodeVariable(const ShaderVariable &variable,
                            const BlockMemberInfo &variableInfo,
                            const std::string &name,
                            const std::string &mappedName) override
        {
            ASSERT(!gl::IsSamplerType(variable.type));
            if (!gl::IsOpaqueType(variable.type))
            {
                (*mInfoOut)[name] = variableInfo;
            }
        }
    
      private:
        BlockLayoutMap *mInfoOut;
    };
    
    template <typename VarT>
    void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
                               const std::string &prefix,
                               BlockLayoutEncoder *encoder,
                               bool inRowMajorLayout,
                               BlockLayoutMap *blockInfoOut)
    {
        BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
        TraverseShaderVariables(fields, inRowMajorLayout, &visitor);
    }
    
    void TraverseStructVariable(const ShaderVariable &variable,
                                bool isRowMajorLayout,
                                ShaderVariableVisitor *visitor)
    {
        const std::vector<ShaderVariable> &fields = variable.fields;
    
        visitor->enterStructAccess(variable, isRowMajorLayout);
        TraverseShaderVariables(fields, isRowMajorLayout, visitor);
        visitor->exitStructAccess(variable, isRowMajorLayout);
    }
    
    void TraverseStructArrayVariable(const ShaderVariable &variable,
                                     bool inRowMajorLayout,
                                     ShaderVariableVisitor *visitor)
    {
        visitor->enterArray(variable);
    
        // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
        // innermost. We make a special case for unsized arrays.
        const unsigned int currentArraySize = variable.getNestedArraySize(0);
        unsigned int count                  = std::max(currentArraySize, 1u);
        for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
        {
            visitor->enterArrayElement(variable, arrayElement);
            ShaderVariable elementVar = variable;
            elementVar.indexIntoArray(arrayElement);
    
            if (variable.arraySizes.size() > 1u)
            {
                TraverseStructArrayVariable(elementVar, inRowMajorLayout, visitor);
            }
            else
            {
                TraverseStructVariable(elementVar, inRowMajorLayout, visitor);
            }
    
            visitor->exitArrayElement(variable, arrayElement);
        }
    
        visitor->exitArray(variable);
    }
    
    void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
                                       unsigned int arrayNestingIndex,
                                       bool isRowMajorMatrix,
                                       ShaderVariableVisitor *visitor)
    {
        visitor->enterArray(variable);
    
        const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
        unsigned int count                  = std::max(currentArraySize, 1u);
        for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
        {
            visitor->enterArrayElement(variable, arrayElement);
    
            ShaderVariable elementVar = variable;
            elementVar.indexIntoArray(arrayElement);
    
            if (arrayNestingIndex + 2u < variable.arraySizes.size())
            {
                TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor);
            }
            else
            {
                if (gl::IsSamplerType(variable.type))
                {
                    visitor->visitSampler(elementVar);
                }
                else
                {
                    visitor->visitVariable(elementVar, isRowMajorMatrix);
                }
            }
    
            visitor->exitArrayElement(variable, arrayElement);
        }
    
        visitor->exitArray(variable);
    }
    
    std::string CollapseNameStack(const std::vector<std::string> &nameStack)
    {
        std::stringstream strstr = sh::InitializeStream<std::stringstream>();
        for (const std::string &part : nameStack)
        {
            strstr << part;
        }
        return strstr.str();
    }
    
    size_t GetStd430BaseAlignment(GLenum variableType, bool isRowMajor)
    {
        GLenum flippedType   = isRowMajor ? variableType : gl::TransposeMatrixType(variableType);
        size_t numComponents = static_cast<size_t>(gl::VariableColumnCount(flippedType));
        return ComponentAlignment(numComponents);
    }
    
    class BaseAlignmentVisitor : public ShaderVariableVisitor
    {
      public:
        BaseAlignmentVisitor() = default;
        void visitVariable(const ShaderVariable &variable, bool isRowMajor) override
        {
            size_t baseAlignment = GetStd430BaseAlignment(variable.type, isRowMajor);
            mCurrentAlignment    = std::max(mCurrentAlignment, baseAlignment);
        }
    
        // This is in components rather than bytes.
        size_t getBaseAlignment() const { return mCurrentAlignment; }
    
      private:
        size_t mCurrentAlignment = 0;
    };
    }  // anonymous namespace
    
    // BlockLayoutEncoder implementation.
    BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) {}
    
    BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
                                                   const std::vector<unsigned int> &arraySizes,
                                                   bool isRowMajorMatrix)
    {
        int arrayStride;
        int matrixStride;
    
        getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
    
        const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
                                         static_cast<int>(arrayStride * kBytesPerComponent),
                                         static_cast<int>(matrixStride * kBytesPerComponent),
                                         isRowMajorMatrix);
    
        advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
    
        return memberInfo;
    }
    
    size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
    {
        size_t currentOffset = mCurrentOffset;
        mCurrentOffset       = 0;
        BlockEncoderVisitor visitor("", "", this);
        enterAggregateType(structVar);
        TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
        exitAggregateType(structVar);
        size_t structVarSize = getCurrentOffset();
        mCurrentOffset       = currentOffset;
        return structVarSize;
    }
    
    // static
    size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
    {
        return (info.offset / kBytesPerComponent) / kComponentsPerRegister;
    }
    
    // static
    size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
    {
        return (info.offset / kBytesPerComponent) % kComponentsPerRegister;
    }
    
    void BlockLayoutEncoder::align(size_t baseAlignment)
    {
        mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, baseAlignment);
    }
    
    // DummyBlockEncoder implementation.
    void DummyBlockEncoder::getBlockLayoutInfo(GLenum type,
                                               const std::vector<unsigned int> &arraySizes,
                                               bool isRowMajorMatrix,
                                               int *arrayStrideOut,
                                               int *matrixStrideOut)
    {
        *arrayStrideOut  = 0;
        *matrixStrideOut = 0;
    }
    
    // Std140BlockEncoder implementation.
    Std140BlockEncoder::Std140BlockEncoder() {}
    
    void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar)
    {
        align(getBaseAlignment(structVar));
    }
    
    void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar)
    {
        align(getBaseAlignment(structVar));
    }
    
    void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
                                                const std::vector<unsigned int> &arraySizes,
                                                bool isRowMajorMatrix,
                                                int *arrayStrideOut,
                                                int *matrixStrideOut)
    {
        // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
        ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
    
        size_t baseAlignment = 0;
        int matrixStride     = 0;
        int arrayStride      = 0;
    
        if (gl::IsMatrixType(type))
        {
            baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix);
            matrixStride  = static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix));
    
            if (!arraySizes.empty())
            {
                const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
                arrayStride =
                    static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters);
            }
        }
        else if (!arraySizes.empty())
        {
            baseAlignment = static_cast<int>(getTypeBaseAlignment(type, false));
            arrayStride   = static_cast<int>(getTypeBaseAlignment(type, false));
        }
        else
        {
            const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type));
            baseAlignment              = ComponentAlignment(numComponents);
        }
    
        mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
    
        *matrixStrideOut = matrixStride;
        *arrayStrideOut  = arrayStride;
    }
    
    void Std140BlockEncoder::advanceOffset(GLenum type,
                                           const std::vector<unsigned int> &arraySizes,
                                           bool isRowMajorMatrix,
                                           int arrayStride,
                                           int matrixStride)
    {
        if (!arraySizes.empty())
        {
            mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes);
        }
        else if (gl::IsMatrixType(type))
        {
            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
            mCurrentOffset += matrixStride * numRegisters;
        }
        else
        {
            mCurrentOffset += gl::VariableComponentCount(type);
        }
    }
    
    size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const
    {
        return kComponentsPerRegister;
    }
    
    size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
    {
        return kComponentsPerRegister;
    }
    
    // Std430BlockEncoder implementation.
    Std430BlockEncoder::Std430BlockEncoder() {}
    
    size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const
    {
        if (shaderVar.isStruct())
        {
            BaseAlignmentVisitor visitor;
            TraverseShaderVariables(shaderVar.fields, false, &visitor);
            return visitor.getBaseAlignment();
        }
    
        return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
    }
    
    size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
    {
        return GetStd430BaseAlignment(type, isRowMajorMatrix);
    }
    
    void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
                               const std::string &prefix,
                               BlockLayoutEncoder *encoder,
                               BlockLayoutMap *blockInfoOut)
    {
        // Matrix packing is always recorded in individual fields, so they'll set the row major layout
        // flag to true if needed.
        GetInterfaceBlockInfo(fields, prefix, encoder, false, blockInfoOut);
    }
    
    void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
                             const std::string &prefix,
                             BlockLayoutEncoder *encoder,
                             BlockLayoutMap *blockInfoOut)
    {
        // Matrix packing is always recorded in individual fields, so they'll set the row major layout
        // flag to true if needed.
        GetInterfaceBlockInfo(uniforms, prefix, encoder, false, blockInfoOut);
    }
    
    // VariableNameVisitor implementation.
    VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
                                             const std::string &mappedNamePrefix)
    {
        if (!namePrefix.empty())
        {
            mNameStack.push_back(namePrefix + ".");
        }
    
        if (!mappedNamePrefix.empty())
        {
            mMappedNameStack.push_back(mappedNamePrefix + ".");
        }
    }
    
    VariableNameVisitor::~VariableNameVisitor() = default;
    
    void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
    {
        mNameStack.push_back(structVar.name);
        mMappedNameStack.push_back(structVar.mappedName);
    }
    
    void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
    {
        mNameStack.pop_back();
        mMappedNameStack.pop_back();
    }
    
    void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    {
        mNameStack.push_back(".");
        mMappedNameStack.push_back(".");
    }
    
    void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    {
        mNameStack.pop_back();
        mMappedNameStack.pop_back();
    }
    
    void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
    {
        if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
        {
            mNameStack.push_back(arrayVar.name);
            mMappedNameStack.push_back(arrayVar.mappedName);
        }
    }
    
    void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
    {
        if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
        {
            mNameStack.pop_back();
            mMappedNameStack.pop_back();
        }
    }
    
    void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
                                                unsigned int arrayElement)
    {
        std::stringstream strstr = sh::InitializeStream<std::stringstream>();
        strstr << "[" << arrayElement << "]";
        std::string elementString = strstr.str();
        mNameStack.push_back(elementString);
        mMappedNameStack.push_back(elementString);
    }
    
    void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar,
                                               unsigned int arrayElement)
    {
        mNameStack.pop_back();
        mMappedNameStack.pop_back();
    }
    
    std::string VariableNameVisitor::collapseNameStack() const
    {
        return CollapseNameStack(mNameStack);
    }
    
    std::string VariableNameVisitor::collapseMappedNameStack() const
    {
        return CollapseNameStack(mMappedNameStack);
    }
    
    void VariableNameVisitor::visitSampler(const sh::ShaderVariable &sampler)
    {
        if (!sampler.hasParentArrayIndex())
        {
            mNameStack.push_back(sampler.name);
            mMappedNameStack.push_back(sampler.mappedName);
        }
    
        std::string name       = collapseNameStack();
        std::string mappedName = collapseMappedNameStack();
    
        if (!sampler.hasParentArrayIndex())
        {
            mNameStack.pop_back();
            mMappedNameStack.pop_back();
        }
    
        visitNamedSampler(sampler, name, mappedName);
    }
    
    void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
    {
        if (!variable.hasParentArrayIndex())
        {
            mNameStack.push_back(variable.name);
            mMappedNameStack.push_back(variable.mappedName);
        }
    
        std::string name       = collapseNameStack();
        std::string mappedName = collapseMappedNameStack();
    
        if (!variable.hasParentArrayIndex())
        {
            mNameStack.pop_back();
            mMappedNameStack.pop_back();
        }
    
        visitNamedVariable(variable, isRowMajor, name, mappedName);
    }
    
    // BlockEncoderVisitor implementation.
    BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
                                             const std::string &mappedNamePrefix,
                                             BlockLayoutEncoder *encoder)
        : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
    {}
    
    BlockEncoderVisitor::~BlockEncoderVisitor() = default;
    
    void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    {
        mStructStackSize++;
        if (!mIsTopLevelArrayStrideReady)
        {
            size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
            mTopLevelArrayStride *= structSize;
            mIsTopLevelArrayStrideReady = true;
        }
    
        VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
        mEncoder->enterAggregateType(structVar);
    }
    
    void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    {
        mStructStackSize--;
        mEncoder->exitAggregateType(structVar);
        VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
    }
    
    void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
                                                unsigned int arrayElement)
    {
        if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
        {
            // From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
            // For an active shader storage block member declared as an array of an aggregate type,
            // an entry will be generated only for the first array element, regardless of its type.
            // Such block members are referred to as top-level arrays. If the block member is an
            // aggregate type, the enumeration rules are then applied recursively.
            if (arrayElement == 0)
            {
                mTopLevelArraySize          = arrayVar.getOutermostArraySize();
                mTopLevelArrayStride        = arrayVar.getInnerArraySizeProduct();
                mIsTopLevelArrayStrideReady = false;
            }
            else
            {
                mSkipEnabled = true;
            }
        }
        VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
    }
    
    void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
                                               unsigned int arrayElement)
    {
        if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
        {
            mTopLevelArraySize          = 1;
            mTopLevelArrayStride        = 0;
            mIsTopLevelArrayStrideReady = true;
            mSkipEnabled                = false;
        }
        VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
    }
    
    void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
                                                 bool isRowMajor,
                                                 const std::string &name,
                                                 const std::string &mappedName)
    {
        std::vector<unsigned int> innermostArraySize;
    
        if (variable.isArray())
        {
            innermostArraySize.push_back(variable.getNestedArraySize(0));
        }
        BlockMemberInfo variableInfo =
            mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
        if (!mIsTopLevelArrayStrideReady)
        {
            ASSERT(mTopLevelArrayStride);
            mTopLevelArrayStride *= variableInfo.arrayStride;
            mIsTopLevelArrayStrideReady = true;
        }
        variableInfo.topLevelArrayStride = mTopLevelArrayStride;
        encodeVariable(variable, variableInfo, name, mappedName);
    }
    
    void TraverseShaderVariable(const ShaderVariable &variable,
                                bool isRowMajorLayout,
                                ShaderVariableVisitor *visitor)
    {
        bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
        bool isRowMajor     = rowMajorLayout && gl::IsMatrixType(variable.type);
    
        if (variable.isStruct())
        {
            visitor->enterStruct(variable);
            if (variable.isArray())
            {
                TraverseStructArrayVariable(variable, rowMajorLayout, visitor);
            }
            else
            {
                TraverseStructVariable(variable, rowMajorLayout, visitor);
            }
            visitor->exitStruct(variable);
        }
        else if (variable.isArrayOfArrays())
        {
            TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
        }
        else if (gl::IsSamplerType(variable.type))
        {
            visitor->visitSampler(variable);
        }
        else
        {
            visitor->visitVariable(variable, isRowMajor);
        }
    }
    }  // namespace sh