Edit

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

Branch :

  • Show log

    Commit

  • Author : Tim Van Patten
    Date : 2019-09-04 15:39:58
    Hash : 90a58622
    Message : Refactor ShaderVariable to Remove Specializations The following structs are being refactored and moved into the parent struct ShaderVariable: VariableWithLocation Uniform Attribute OutputVariable InterfaceBlockField Varying Bug: angleproject:3899 Test: CQ Change-Id: I389eb3ab4ed44a360e09fca75ecc78d64a277f83 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1785877 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com> Commit-Queue: Tim Van Patten <timvp@google.com>

  • 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<ShaderVariable> &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<ShaderVariable> &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);
        }
        mArraySizeStack.push_back(arrayVar.getOutermostArraySize());
    }
    
    void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
    {
        if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
        {
            mNameStack.pop_back();
            mMappedNameStack.pop_back();
        }
        mArraySizeStack.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, mArraySizeStack);
    }
    
    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, mArraySizeStack);
    }
    
    // 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,
                                                 const std::vector<unsigned int> &arraySizes)
    {
        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