Edit

kc3-lang/angle/src/compiler/translator/ShaderVars.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/ShaderVars.cpp
  • //
    // Copyright 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.
    //
    // ShaderVars.cpp:
    //  Methods for GL variable types (varyings, uniforms, etc)
    //
    
    #include <GLSLANG/ShaderLang.h>
    
    #include "common/debug.h"
    #include "common/utilities.h"
    
    namespace sh
    {
    
    namespace
    {
    
    InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation)
    {
        return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation);
    }
    }  // namespace
    // The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion
    // on Khronos.org, clarifies that a smooth/flat mismatch produces a link error,
    // but auxiliary qualifier mismatch (centroid) does not.
    bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
    {
        return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
    }
    
    ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
    
    ShaderVariable::ShaderVariable(GLenum typeIn)
        : type(typeIn),
          precision(0),
          staticUse(false),
          active(false),
          isRowMajorLayout(false),
          location(-1),
          hasImplicitLocation(false),
          binding(-1),
          imageUnitFormat(GL_NONE),
          offset(-1),
          readonly(false),
          writeonly(false),
          isFragmentInOut(false),
          index(-1),
          yuv(false),
          interpolation(INTERPOLATION_SMOOTH),
          isInvariant(false),
          isShaderIOBlock(false),
          isPatch(false),
          texelFetchStaticUse(false),
          flattenedOffsetInParentArrays(-1)
    {}
    
    ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
    {
        ASSERT(arraySizeIn != 0);
        arraySizes.push_back(arraySizeIn);
    }
    
    ShaderVariable::~ShaderVariable() {}
    
    ShaderVariable::ShaderVariable(const ShaderVariable &other)
        : type(other.type),
          precision(other.precision),
          name(other.name),
          mappedName(other.mappedName),
          arraySizes(other.arraySizes),
          staticUse(other.staticUse),
          active(other.active),
          fields(other.fields),
          structOrBlockName(other.structOrBlockName),
          mappedStructOrBlockName(other.mappedStructOrBlockName),
          isRowMajorLayout(other.isRowMajorLayout),
          location(other.location),
          hasImplicitLocation(other.hasImplicitLocation),
          binding(other.binding),
          imageUnitFormat(other.imageUnitFormat),
          offset(other.offset),
          readonly(other.readonly),
          writeonly(other.writeonly),
          isFragmentInOut(other.isFragmentInOut),
          index(other.index),
          yuv(other.yuv),
          interpolation(other.interpolation),
          isInvariant(other.isInvariant),
          isShaderIOBlock(other.isShaderIOBlock),
          isPatch(other.isPatch),
          texelFetchStaticUse(other.texelFetchStaticUse),
          flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
    {}
    
    ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
    {
        type                          = other.type;
        precision                     = other.precision;
        name                          = other.name;
        mappedName                    = other.mappedName;
        arraySizes                    = other.arraySizes;
        staticUse                     = other.staticUse;
        active                        = other.active;
        fields                        = other.fields;
        structOrBlockName             = other.structOrBlockName;
        mappedStructOrBlockName       = other.mappedStructOrBlockName;
        isRowMajorLayout              = other.isRowMajorLayout;
        flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
        location                      = other.location;
        hasImplicitLocation           = other.hasImplicitLocation;
        binding                       = other.binding;
        imageUnitFormat               = other.imageUnitFormat;
        offset                        = other.offset;
        readonly                      = other.readonly;
        writeonly                     = other.writeonly;
        isFragmentInOut               = other.isFragmentInOut;
        index                         = other.index;
        yuv                           = other.yuv;
        interpolation                 = other.interpolation;
        isInvariant                   = other.isInvariant;
        isShaderIOBlock               = other.isShaderIOBlock;
        isPatch                       = other.isPatch;
        texelFetchStaticUse           = other.texelFetchStaticUse;
        return *this;
    }
    
    bool ShaderVariable::operator==(const ShaderVariable &other) const
    {
        if (type != other.type || precision != other.precision || name != other.name ||
            mappedName != other.mappedName || arraySizes != other.arraySizes ||
            staticUse != other.staticUse || active != other.active ||
            fields.size() != other.fields.size() || structOrBlockName != other.structOrBlockName ||
            mappedStructOrBlockName != other.mappedStructOrBlockName ||
            isRowMajorLayout != other.isRowMajorLayout || location != other.location ||
            hasImplicitLocation != other.hasImplicitLocation || binding != other.binding ||
            imageUnitFormat != other.imageUnitFormat || offset != other.offset ||
            readonly != other.readonly || writeonly != other.writeonly || index != other.index ||
            yuv != other.yuv || interpolation != other.interpolation ||
            isInvariant != other.isInvariant || isShaderIOBlock != other.isShaderIOBlock ||
            isPatch != other.isPatch || texelFetchStaticUse != other.texelFetchStaticUse ||
            isFragmentInOut != other.isFragmentInOut)
        {
            return false;
        }
        for (size_t ii = 0; ii < fields.size(); ++ii)
        {
            if (fields[ii] != other.fields[ii])
                return false;
        }
        return true;
    }
    
    void ShaderVariable::setArraySize(unsigned int size)
    {
        arraySizes.clear();
        if (size != 0)
        {
            arraySizes.push_back(size);
        }
    }
    
    unsigned int ShaderVariable::getInnerArraySizeProduct() const
    {
        unsigned int arraySizeProduct = 1u;
        for (size_t idx = 1; idx < arraySizes.size(); ++idx)
        {
            arraySizeProduct *= getNestedArraySize(static_cast<unsigned int>(idx));
        }
        return arraySizeProduct;
    }
    
    unsigned int ShaderVariable::getArraySizeProduct() const
    {
        return gl::ArraySizeProduct(arraySizes);
    }
    
    void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
    {
        ASSERT(isArray());
        flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
        arraySizes.pop_back();
    }
    
    unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
    {
        ASSERT(arraySizes.size() > arrayNestingIndex);
        unsigned int arraySize = arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
    
        if (arraySize == 0)
        {
            // Unsized array, so give it at least 1 entry
            arraySize = 1;
        }
    
        return arraySize;
    }
    
    unsigned int ShaderVariable::getBasicTypeElementCount() const
    {
        // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
        // for each array element when dealing with an array of arrays or an array of structs.
        ASSERT(!isArrayOfArrays());
        ASSERT(!isStruct() || !isArray());
    
        // GLES 3.1 Nov 2016 page 82.
        if (isArray())
        {
            return getOutermostArraySize();
        }
        return 1u;
    }
    
    unsigned int ShaderVariable::getExternalSize() const
    {
        unsigned int memorySize = 0;
    
        if (isStruct())
        {
            // Have a structure, need to compute the structure size.
            for (const auto &field : fields)
            {
                memorySize += field.getExternalSize();
            }
        }
        else
        {
            memorySize += gl::VariableExternalSize(type);
        }
    
        // multiply by array size to get total memory size of this variable / struct.
        memorySize *= getArraySizeProduct();
    
        return memorySize;
    }
    
    bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
                                              const ShaderVariable **leafVar,
                                              std::string *originalFullName) const
    {
        ASSERT(leafVar && originalFullName);
        // There are three cases:
        // 1) the top variable is of struct type;
        // 2) the top variable is an array;
        // 3) otherwise.
        size_t pos = mappedFullName.find_first_of(".[");
    
        if (pos == std::string::npos)
        {
            // Case 3.
            if (mappedFullName != this->mappedName)
                return false;
            *originalFullName = this->name;
            *leafVar          = this;
            return true;
        }
        else
        {
            std::string topName = mappedFullName.substr(0, pos);
            if (topName != this->mappedName)
                return false;
            std::string originalName = this->name;
            std::string remaining;
            if (mappedFullName[pos] == '[')
            {
                // Case 2.
                size_t closePos = mappedFullName.find_first_of(']');
                if (closePos < pos || closePos == std::string::npos)
                    return false;
                // Append '[index]'.
                originalName += mappedFullName.substr(pos, closePos - pos + 1);
                if (closePos + 1 == mappedFullName.size())
                {
                    *originalFullName = originalName;
                    *leafVar          = this;
                    return true;
                }
                else
                {
                    // In the form of 'a[0].b', so after ']', '.' is expected.
                    if (mappedFullName[closePos + 1] != '.')
                        return false;
                    remaining = mappedFullName.substr(closePos + 2);  // Skip "]."
                }
            }
            else
            {
                // Case 1.
                remaining = mappedFullName.substr(pos + 1);  // Skip "."
            }
            for (size_t ii = 0; ii < this->fields.size(); ++ii)
            {
                const ShaderVariable *fieldVar = nullptr;
                std::string originalFieldName;
                bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
                if (found)
                {
                    *originalFullName = originalName + "." + originalFieldName;
                    *leafVar          = fieldVar;
                    return true;
                }
            }
            return false;
        }
    }
    
    const sh::ShaderVariable *ShaderVariable::findField(const std::string &fullName,
                                                        uint32_t *fieldIndexOut) const
    {
        if (fields.empty())
        {
            return nullptr;
        }
        size_t pos = fullName.find_first_of(".");
        std::string topName, fieldName;
        if (pos == std::string::npos)
        {
            // If this is a shader I/O block without an instance name, return the field given only the
            // field name.
            if (!isShaderIOBlock || !name.empty())
            {
                return nullptr;
            }
    
            fieldName = fullName;
        }
        else
        {
            std::string baseName = isShaderIOBlock ? structOrBlockName : name;
            topName              = fullName.substr(0, pos);
            if (topName != baseName)
            {
                return nullptr;
            }
            fieldName = fullName.substr(pos + 1);
        }
        if (fieldName.empty())
        {
            return nullptr;
        }
        for (size_t field = 0; field < fields.size(); ++field)
        {
            if (fields[field].name == fieldName)
            {
                *fieldIndexOut = static_cast<GLuint>(field);
                return &fields[field];
            }
        }
        return nullptr;
    }
    
    bool ShaderVariable::isBuiltIn() const
    {
        return gl::IsBuiltInName(name);
    }
    
    bool ShaderVariable::isEmulatedBuiltIn() const
    {
        return isBuiltIn() && name != mappedName;
    }
    
    bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
                                                  bool matchPrecision,
                                                  bool matchName) const
    {
        if (type != other.type)
            return false;
        if (matchPrecision && precision != other.precision)
            return false;
        if (matchName && name != other.name)
            return false;
        ASSERT(!matchName || mappedName == other.mappedName);
        if (arraySizes != other.arraySizes)
            return false;
        if (isRowMajorLayout != other.isRowMajorLayout)
            return false;
        if (fields.size() != other.fields.size())
            return false;
    
        // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
        // Variables declared as structures are considered to match in type if and only if structure
        // members match in name, type, qualification, and declaration order.
        for (size_t ii = 0; ii < fields.size(); ++ii)
        {
            if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
            {
                return false;
            }
        }
        if (structOrBlockName != other.structOrBlockName ||
            mappedStructOrBlockName != other.mappedStructOrBlockName)
            return false;
        return true;
    }
    
    void ShaderVariable::updateEffectiveLocation(const sh::ShaderVariable &parent)
    {
        if ((location < 0 || hasImplicitLocation) && !parent.hasImplicitLocation)
        {
            location = parent.location;
        }
    }
    
    void ShaderVariable::resetEffectiveLocation()
    {
        if (hasImplicitLocation)
        {
            location = -1;
        }
    }
    
    bool ShaderVariable::isSameUniformAtLinkTime(const ShaderVariable &other) const
    {
        // Enforce a consistent match.
        // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
        if (binding != -1 && other.binding != -1 && binding != other.binding)
        {
            return false;
        }
        if (imageUnitFormat != other.imageUnitFormat)
        {
            return false;
        }
        if (location != -1 && other.location != -1 && location != other.location)
        {
            return false;
        }
        if (offset != other.offset)
        {
            return false;
        }
        if (readonly != other.readonly || writeonly != other.writeonly)
        {
            return false;
        }
        return ShaderVariable::isSameVariableAtLinkTime(other, true, true);
    }
    
    bool ShaderVariable::isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable &other) const
    {
        return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
    }
    
    bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other) const
    {
        return isSameVaryingAtLinkTime(other, 100);
    }
    
    bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int shaderVersion) const
    {
        return ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
               InterpolationTypesMatch(interpolation, other.interpolation) &&
               (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
               (isPatch == other.isPatch) && location == other.location &&
               (isSameNameAtLinkTime(other) || (shaderVersion >= 310 && location >= 0));
    }
    
    bool ShaderVariable::isSameNameAtLinkTime(const ShaderVariable &other) const
    {
        if (isShaderIOBlock != other.isShaderIOBlock)
        {
            return false;
        }
    
        if (isShaderIOBlock)
        {
            // Shader I/O blocks match by block name.
            return structOrBlockName == other.structOrBlockName;
        }
    
        // Otherwise match by name.
        return name == other.name;
    }
    
    InterfaceBlock::InterfaceBlock()
        : arraySize(0),
          layout(BLOCKLAYOUT_PACKED),
          isRowMajorLayout(false),
          binding(-1),
          staticUse(false),
          active(false),
          blockType(BlockType::BLOCK_UNIFORM)
    {}
    
    InterfaceBlock::~InterfaceBlock() {}
    
    InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
        : name(other.name),
          mappedName(other.mappedName),
          instanceName(other.instanceName),
          arraySize(other.arraySize),
          layout(other.layout),
          isRowMajorLayout(other.isRowMajorLayout),
          binding(other.binding),
          staticUse(other.staticUse),
          active(other.active),
          blockType(other.blockType),
          fields(other.fields)
    {}
    
    InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
    {
        name             = other.name;
        mappedName       = other.mappedName;
        instanceName     = other.instanceName;
        arraySize        = other.arraySize;
        layout           = other.layout;
        isRowMajorLayout = other.isRowMajorLayout;
        binding          = other.binding;
        staticUse        = other.staticUse;
        active           = other.active;
        blockType        = other.blockType;
        fields           = other.fields;
        return *this;
    }
    
    std::string InterfaceBlock::fieldPrefix() const
    {
        return instanceName.empty() ? "" : name;
    }
    
    std::string InterfaceBlock::fieldMappedPrefix() const
    {
        return instanceName.empty() ? "" : mappedName;
    }
    
    bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
    {
        if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
            layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
            binding != other.binding || blockType != other.blockType ||
            fields.size() != other.fields.size())
        {
            return false;
        }
    
        for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
        {
            if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
            {
                return false;
            }
        }
    
        return true;
    }
    
    bool InterfaceBlock::isBuiltIn() const
    {
        return gl::IsBuiltInName(name);
    }
    
    void WorkGroupSize::fill(int fillValue)
    {
        localSizeQualifiers[0] = fillValue;
        localSizeQualifiers[1] = fillValue;
        localSizeQualifiers[2] = fillValue;
    }
    
    void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
    {
        localSizeQualifiers[0] = localSizeX;
        localSizeQualifiers[1] = localSizeY;
        localSizeQualifiers[2] = localSizeZ;
    }
    
    // check that if one of them is less than 1, then all of them are.
    // Or if one is positive, then all of them are positive.
    bool WorkGroupSize::isLocalSizeValid() const
    {
        return (
            (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
            (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
    }
    
    bool WorkGroupSize::isAnyValueSet() const
    {
        return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
    }
    
    bool WorkGroupSize::isDeclared() const
    {
        bool localSizeDeclared = localSizeQualifiers[0] > 0;
        ASSERT(isLocalSizeValid());
        return localSizeDeclared;
    }
    
    bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
    {
        for (size_t i = 0u; i < size(); ++i)
        {
            bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
                           (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
                           (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
            if (!result)
            {
                return false;
            }
        }
        return true;
    }
    
    int &WorkGroupSize::operator[](size_t index)
    {
        ASSERT(index < size());
        return localSizeQualifiers[index];
    }
    
    int WorkGroupSize::operator[](size_t index) const
    {
        ASSERT(index < size());
        return localSizeQualifiers[index];
    }
    
    size_t WorkGroupSize::size() const
    {
        return 3u;
    }
    
    }  // namespace sh