Edit

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

Branch :

  • Show log

    Commit

  • Author : Mohan Maiya
    Date : 2021-02-24 09:49:42
    Hash : 550f2a3e
    Message : Vulkan: Shader support for EXT_shader_framebuffer_fetch_non_coherent Translator can accept gl_LastFragData and 'inout' variable to gain access to framebuffer attachment data. The Vulkan translator replaces it with the SubpassInput type variable. Note that this works only for the noncoherent version of the extension. Bug: angleproject:5454 Test: *EXTShaderFramebufferFetchNoncoherent*.* Change-Id: I392f84ee3ad3eb9fbd09d0b7ff83731a9a3f33f6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2598060 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Mohan Maiya <m.maiya@samsung.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,
                               bool onlyActiveVariables,
                               BlockLayoutMap *blockInfoOut)
    {
        BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
        if (onlyActiveVariables)
        {
            TraverseActiveShaderVariables(fields, inRowMajorLayout, &visitor);
        }
        else
        {
            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);
        for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++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) || gl::IsImageType(variable.type) ||
                    variable.isFragmentInOut)
                {
                    visitor->visitOpaqueObject(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);
    }
    
    // StubBlockEncoder implementation.
    void StubBlockEncoder::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.
        // Iterates over all variables.
        GetInterfaceBlockInfo(fields, prefix, encoder, false, false, blockInfoOut);
    }
    
    void GetActiveUniformBlockInfo(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.
        // Iterates only over the active variables.
        GetInterfaceBlockInfo(uniforms, prefix, encoder, false, true, 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::visitOpaqueObject(const sh::ShaderVariable &variable)
    {
        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();
        }
    
        visitNamedOpaqueObject(variable, 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) || gl::IsImageType(variable.type) ||
                 variable.isFragmentInOut)
        {
            visitor->visitOpaqueObject(variable);
        }
        else
        {
            visitor->visitVariable(variable, isRowMajor);
        }
    }
    }  // namespace sh