Edit

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

Branch :

  • Show log

    Commit

  • Author : Qin Jiajia
    Date : 2018-09-28 14:16:06
    Hash : 6d765b07
    Message : ES31: Fix some bugs in ShaderStorageBlockOutputHLSL When EOpIndexDirect/EOpIndexIndirect/EOpIndexDirectStruct/TIntermSwizzle appear in [] in ssbo access chain, we should transfer the process of them to OutputHLSL. For example: instance.v[gl_GlobalInvocationID.x] = data; // becomes float_Store(dx_instance, 0 + 16 * gl_GlobalInvocationID.x, _data); instance.v[s.index[0].x] = data; // becomes float_Store(dx_instance, 0 + 16 * _s.index[0].x, _data); Bug: angleproject:1951 Change-Id: I333e238400a10a799a6294f8759cf9c4ef2451c8 Reviewed-on: https://chromium-review.googlesource.com/c/1250661 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>

  • src/compiler/translator/util.cpp
  • //
    // Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "compiler/translator/util.h"
    
    #include <limits>
    
    #include "common/utilities.h"
    #include "compiler/preprocessor/numeric_lex.h"
    #include "compiler/translator/ImmutableStringBuilder.h"
    #include "compiler/translator/SymbolTable.h"
    
    bool atoi_clamp(const char *str, unsigned int *value)
    {
        bool success = angle::pp::numeric_lex_int(str, value);
        if (!success)
            *value = std::numeric_limits<unsigned int>::max();
        return success;
    }
    
    namespace sh
    {
    
    namespace
    {
    
    bool IsInterpolationIn(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqSmoothIn:
            case EvqFlatIn:
            case EvqCentroidIn:
                return true;
            default:
                return false;
        }
    }
    
    }  // anonymous namespace
    
    float NumericLexFloat32OutOfRangeToInfinity(const std::string &str)
    {
        // Parses a decimal string using scientific notation into a floating point number.
        // Out-of-range values are converted to infinity. Values that are too small to be
        // represented are converted to zero.
    
        // The mantissa in decimal scientific notation. The magnitude of the mantissa integer does not
        // matter.
        unsigned int decimalMantissa = 0;
        size_t i                     = 0;
        bool decimalPointSeen        = false;
        bool nonZeroSeenInMantissa   = false;
    
        // The exponent offset reflects the position of the decimal point.
        int exponentOffset = -1;
    
        // This is just a counter for how many decimal digits are written to decimalMantissa.
        int mantissaDecimalDigits = 0;
    
        while (i < str.length())
        {
            const char c = str[i];
            if (c == 'e' || c == 'E')
            {
                break;
            }
            if (c == '.')
            {
                decimalPointSeen = true;
                ++i;
                continue;
            }
    
            unsigned int digit = static_cast<unsigned int>(c - '0');
            ASSERT(digit < 10u);
            if (digit != 0u)
            {
                nonZeroSeenInMantissa = true;
            }
            if (nonZeroSeenInMantissa)
            {
                // Add bits to the mantissa until space runs out in 32-bit int. This should be
                // enough precision to make the resulting binary mantissa accurate to 1 ULP.
                if (decimalMantissa <= (std::numeric_limits<unsigned int>::max() - 9u) / 10u)
                {
                    decimalMantissa = decimalMantissa * 10u + digit;
                    ++mantissaDecimalDigits;
                }
                if (!decimalPointSeen)
                {
                    ++exponentOffset;
                }
            }
            else if (decimalPointSeen)
            {
                --exponentOffset;
            }
            ++i;
        }
        if (decimalMantissa == 0)
        {
            return 0.0f;
        }
        int exponent = 0;
        if (i < str.length())
        {
            ASSERT(str[i] == 'e' || str[i] == 'E');
            ++i;
            bool exponentOutOfRange = false;
            bool negativeExponent   = false;
            if (str[i] == '-')
            {
                negativeExponent = true;
                ++i;
            }
            else if (str[i] == '+')
            {
                ++i;
            }
            while (i < str.length())
            {
                const char c       = str[i];
                unsigned int digit = static_cast<unsigned int>(c - '0');
                ASSERT(digit < 10u);
                if (exponent <= (std::numeric_limits<int>::max() - 9) / 10)
                {
                    exponent = exponent * 10 + digit;
                }
                else
                {
                    exponentOutOfRange = true;
                }
                ++i;
            }
            if (negativeExponent)
            {
                exponent = -exponent;
            }
            if (exponentOutOfRange)
            {
                if (negativeExponent)
                {
                    return 0.0f;
                }
                else
                {
                    return std::numeric_limits<float>::infinity();
                }
            }
        }
        // Do the calculation in 64-bit to avoid overflow.
        long long exponentLong =
            static_cast<long long>(exponent) + static_cast<long long>(exponentOffset);
        if (exponentLong > std::numeric_limits<float>::max_exponent10)
        {
            return std::numeric_limits<float>::infinity();
        }
        else if (exponentLong < std::numeric_limits<float>::min_exponent10)
        {
            return 0.0f;
        }
        // The exponent is in range, so we need to actually evaluate the float.
        exponent     = static_cast<int>(exponentLong);
        double value = decimalMantissa;
    
        // Calculate the exponent offset to normalize the mantissa.
        int normalizationExponentOffset = 1 - mantissaDecimalDigits;
        // Apply the exponent.
        value *= std::pow(10.0, static_cast<double>(exponent + normalizationExponentOffset));
        if (value > static_cast<double>(std::numeric_limits<float>::max()))
        {
            return std::numeric_limits<float>::infinity();
        }
        if (value < static_cast<double>(std::numeric_limits<float>::min()))
        {
            return 0.0f;
        }
        return static_cast<float>(value);
    }
    
    bool strtof_clamp(const std::string &str, float *value)
    {
        // Custom float parsing that can handle the following corner cases:
        //   1. The decimal mantissa is very small but the exponent is very large, putting the resulting
        //   number inside the float range.
        //   2. The decimal mantissa is very large but the exponent is very small, putting the resulting
        //   number inside the float range.
        //   3. The value is out-of-range and should be evaluated as infinity.
        //   4. The value is too small and should be evaluated as zero.
        // See ESSL 3.00.6 section 4.1.4 for the relevant specification.
        *value = NumericLexFloat32OutOfRangeToInfinity(str);
        return !gl::isInf(*value);
    }
    
    GLenum GLVariableType(const TType &type)
    {
        if (type.getBasicType() == EbtFloat)
        {
            if (type.isVector())
            {
                switch (type.getNominalSize())
                {
                    case 2:
                        return GL_FLOAT_VEC2;
                    case 3:
                        return GL_FLOAT_VEC3;
                    case 4:
                        return GL_FLOAT_VEC4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return GL_NONE;
    #endif
                }
            }
            else if (type.isMatrix())
            {
                switch (type.getCols())
                {
                    case 2:
                        switch (type.getRows())
                        {
                            case 2:
                                return GL_FLOAT_MAT2;
                            case 3:
                                return GL_FLOAT_MAT2x3;
                            case 4:
                                return GL_FLOAT_MAT2x4;
                            default:
                                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                                return GL_NONE;
    #endif
                        }
    
                    case 3:
                        switch (type.getRows())
                        {
                            case 2:
                                return GL_FLOAT_MAT3x2;
                            case 3:
                                return GL_FLOAT_MAT3;
                            case 4:
                                return GL_FLOAT_MAT3x4;
                            default:
                                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                                return GL_NONE;
    #endif
                        }
    
                    case 4:
                        switch (type.getRows())
                        {
                            case 2:
                                return GL_FLOAT_MAT4x2;
                            case 3:
                                return GL_FLOAT_MAT4x3;
                            case 4:
                                return GL_FLOAT_MAT4;
                            default:
                                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                                return GL_NONE;
    #endif
                        }
    
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return GL_NONE;
    #endif
                }
            }
            else
            {
                return GL_FLOAT;
            }
        }
        else if (type.getBasicType() == EbtInt)
        {
            if (type.isVector())
            {
                switch (type.getNominalSize())
                {
                    case 2:
                        return GL_INT_VEC2;
                    case 3:
                        return GL_INT_VEC3;
                    case 4:
                        return GL_INT_VEC4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return GL_NONE;
    #endif
                }
            }
            else
            {
                ASSERT(!type.isMatrix());
                return GL_INT;
            }
        }
        else if (type.getBasicType() == EbtUInt)
        {
            if (type.isVector())
            {
                switch (type.getNominalSize())
                {
                    case 2:
                        return GL_UNSIGNED_INT_VEC2;
                    case 3:
                        return GL_UNSIGNED_INT_VEC3;
                    case 4:
                        return GL_UNSIGNED_INT_VEC4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return GL_NONE;
    #endif
                }
            }
            else
            {
                ASSERT(!type.isMatrix());
                return GL_UNSIGNED_INT;
            }
        }
        else if (type.getBasicType() == EbtBool)
        {
            if (type.isVector())
            {
                switch (type.getNominalSize())
                {
                    case 2:
                        return GL_BOOL_VEC2;
                    case 3:
                        return GL_BOOL_VEC3;
                    case 4:
                        return GL_BOOL_VEC4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return GL_NONE;
    #endif
                }
            }
            else
            {
                ASSERT(!type.isMatrix());
                return GL_BOOL;
            }
        }
    
        switch (type.getBasicType())
        {
            case EbtSampler2D:
                return GL_SAMPLER_2D;
            case EbtSampler3D:
                return GL_SAMPLER_3D;
            case EbtSamplerCube:
                return GL_SAMPLER_CUBE;
            case EbtSamplerExternalOES:
                return GL_SAMPLER_EXTERNAL_OES;
            case EbtSamplerExternal2DY2YEXT:
                return GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
            case EbtSampler2DRect:
                return GL_SAMPLER_2D_RECT_ANGLE;
            case EbtSampler2DArray:
                return GL_SAMPLER_2D_ARRAY;
            case EbtSampler2DMS:
                return GL_SAMPLER_2D_MULTISAMPLE;
            case EbtSampler2DMSArray:
                return GL_SAMPLER_2D_MULTISAMPLE_ARRAY;
            case EbtISampler2D:
                return GL_INT_SAMPLER_2D;
            case EbtISampler3D:
                return GL_INT_SAMPLER_3D;
            case EbtISamplerCube:
                return GL_INT_SAMPLER_CUBE;
            case EbtISampler2DArray:
                return GL_INT_SAMPLER_2D_ARRAY;
            case EbtISampler2DMS:
                return GL_INT_SAMPLER_2D_MULTISAMPLE;
            case EbtISampler2DMSArray:
                return GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
            case EbtUSampler2D:
                return GL_UNSIGNED_INT_SAMPLER_2D;
            case EbtUSampler3D:
                return GL_UNSIGNED_INT_SAMPLER_3D;
            case EbtUSamplerCube:
                return GL_UNSIGNED_INT_SAMPLER_CUBE;
            case EbtUSampler2DArray:
                return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
            case EbtUSampler2DMS:
                return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
            case EbtUSampler2DMSArray:
                return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
            case EbtSampler2DShadow:
                return GL_SAMPLER_2D_SHADOW;
            case EbtSamplerCubeShadow:
                return GL_SAMPLER_CUBE_SHADOW;
            case EbtSampler2DArrayShadow:
                return GL_SAMPLER_2D_ARRAY_SHADOW;
            case EbtImage2D:
                return GL_IMAGE_2D;
            case EbtIImage2D:
                return GL_INT_IMAGE_2D;
            case EbtUImage2D:
                return GL_UNSIGNED_INT_IMAGE_2D;
            case EbtImage2DArray:
                return GL_IMAGE_2D_ARRAY;
            case EbtIImage2DArray:
                return GL_INT_IMAGE_2D_ARRAY;
            case EbtUImage2DArray:
                return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
            case EbtImage3D:
                return GL_IMAGE_3D;
            case EbtIImage3D:
                return GL_INT_IMAGE_3D;
            case EbtUImage3D:
                return GL_UNSIGNED_INT_IMAGE_3D;
            case EbtImageCube:
                return GL_IMAGE_CUBE;
            case EbtIImageCube:
                return GL_INT_IMAGE_CUBE;
            case EbtUImageCube:
                return GL_UNSIGNED_INT_IMAGE_CUBE;
            case EbtAtomicCounter:
                return GL_UNSIGNED_INT_ATOMIC_COUNTER;
            default:
                UNREACHABLE();
        }
    
        return GL_NONE;
    }
    
    GLenum GLVariablePrecision(const TType &type)
    {
        if (type.getBasicType() == EbtFloat)
        {
            switch (type.getPrecision())
            {
                case EbpHigh:
                    return GL_HIGH_FLOAT;
                case EbpMedium:
                    return GL_MEDIUM_FLOAT;
                case EbpLow:
                    return GL_LOW_FLOAT;
                case EbpUndefined:
                // Should be defined as the default precision by the parser
                default:
                    UNREACHABLE();
            }
        }
        else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt)
        {
            switch (type.getPrecision())
            {
                case EbpHigh:
                    return GL_HIGH_INT;
                case EbpMedium:
                    return GL_MEDIUM_INT;
                case EbpLow:
                    return GL_LOW_INT;
                case EbpUndefined:
                // Should be defined as the default precision by the parser
                default:
                    UNREACHABLE();
            }
        }
    
        // Other types (boolean, sampler) don't have a precision
        return GL_NONE;
    }
    
    ImmutableString ArrayString(const TType &type)
    {
        if (!type.isArray())
            return ImmutableString("");
    
        const TVector<unsigned int> &arraySizes = *type.getArraySizes();
        constexpr const size_t kMaxDecimalDigitsPerSize = 10u;
        ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u));
        for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
             ++arraySizeIter)
        {
            arrayString << "[";
            if (*arraySizeIter > 0)
            {
                arrayString.appendDecimal(*arraySizeIter);
            }
            arrayString << "]";
        }
        return arrayString;
    }
    
    ImmutableString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap)
    {
        if (type.getBasicType() == EbtStruct)
            return HashName(type.getStruct(), hashFunction, nameMap);
        else
            return ImmutableString(type.getBuiltInTypeNameString());
    }
    
    bool IsVaryingOut(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqVaryingOut:
            case EvqSmoothOut:
            case EvqFlatOut:
            case EvqCentroidOut:
            case EvqVertexOut:
            case EvqGeometryOut:
                return true;
    
            default:
                break;
        }
    
        return false;
    }
    
    bool IsVaryingIn(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqVaryingIn:
            case EvqSmoothIn:
            case EvqFlatIn:
            case EvqCentroidIn:
            case EvqFragmentIn:
            case EvqGeometryIn:
                return true;
    
            default:
                break;
        }
    
        return false;
    }
    
    bool IsVarying(TQualifier qualifier)
    {
        return IsVaryingIn(qualifier) || IsVaryingOut(qualifier);
    }
    
    bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier)
    {
        return (qualifier == EvqGeometryIn) ||
               ((shaderType == GL_GEOMETRY_SHADER_EXT) && IsInterpolationIn(qualifier));
    }
    
    InterpolationType GetInterpolationType(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqFlatIn:
            case EvqFlatOut:
                return INTERPOLATION_FLAT;
    
            case EvqSmoothIn:
            case EvqSmoothOut:
            case EvqVertexOut:
            case EvqFragmentIn:
            case EvqVaryingIn:
            case EvqVaryingOut:
            case EvqGeometryIn:
            case EvqGeometryOut:
                return INTERPOLATION_SMOOTH;
    
            case EvqCentroidIn:
            case EvqCentroidOut:
                return INTERPOLATION_CENTROID;
    
            default:
                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                return INTERPOLATION_SMOOTH;
    #endif
        }
    }
    
    TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
    {
        switch (var.type)
        {
            case GL_BOOL:
                return TType(EbtBool);
            case GL_BOOL_VEC2:
                return TType(EbtBool, 2);
            case GL_BOOL_VEC3:
                return TType(EbtBool, 3);
            case GL_BOOL_VEC4:
                return TType(EbtBool, 4);
            case GL_FLOAT:
                return TType(EbtFloat);
            case GL_FLOAT_VEC2:
                return TType(EbtFloat, 2);
            case GL_FLOAT_VEC3:
                return TType(EbtFloat, 3);
            case GL_FLOAT_VEC4:
                return TType(EbtFloat, 4);
            case GL_FLOAT_MAT2:
                return TType(EbtFloat, 2, 2);
            case GL_FLOAT_MAT3:
                return TType(EbtFloat, 3, 3);
            case GL_FLOAT_MAT4:
                return TType(EbtFloat, 4, 4);
            case GL_FLOAT_MAT2x3:
                return TType(EbtFloat, 2, 3);
            case GL_FLOAT_MAT2x4:
                return TType(EbtFloat, 2, 4);
            case GL_FLOAT_MAT3x2:
                return TType(EbtFloat, 3, 2);
            case GL_FLOAT_MAT3x4:
                return TType(EbtFloat, 3, 4);
            case GL_FLOAT_MAT4x2:
                return TType(EbtFloat, 4, 2);
            case GL_FLOAT_MAT4x3:
                return TType(EbtFloat, 4, 3);
            case GL_INT:
                return TType(EbtInt);
            case GL_INT_VEC2:
                return TType(EbtInt, 2);
            case GL_INT_VEC3:
                return TType(EbtInt, 3);
            case GL_INT_VEC4:
                return TType(EbtInt, 4);
            case GL_UNSIGNED_INT:
                return TType(EbtUInt);
            case GL_UNSIGNED_INT_VEC2:
                return TType(EbtUInt, 2);
            case GL_UNSIGNED_INT_VEC3:
                return TType(EbtUInt, 3);
            case GL_UNSIGNED_INT_VEC4:
                return TType(EbtUInt, 4);
            default:
                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                return TType();
    #endif
        }
    }
    
    void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable)
    {
        TIntermDeclaration *declaration = new TIntermDeclaration();
        declaration->appendDeclarator(new TIntermSymbol(variable));
    
        TIntermSequence *globalSequence = root->getSequence();
        globalSequence->insert(globalSequence->begin(), declaration);
    }
    
    // GLSL ES 1.0.17 4.6.1 The Invariant Qualifier
    bool CanBeInvariantESSL1(TQualifier qualifier)
    {
        return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) ||
               IsBuiltinOutputVariable(qualifier) ||
               (IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing);
    }
    
    // GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier
    // GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier
    bool CanBeInvariantESSL3OrGreater(TQualifier qualifier)
    {
        return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut ||
               IsBuiltinOutputVariable(qualifier);
    }
    
    bool IsBuiltinOutputVariable(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqPosition:
            case EvqPointSize:
            case EvqFragDepth:
            case EvqFragDepthEXT:
            case EvqFragColor:
            case EvqSecondaryFragColorEXT:
            case EvqFragData:
            case EvqSecondaryFragDataEXT:
                return true;
            default:
                break;
        }
        return false;
    }
    
    bool IsBuiltinFragmentInputVariable(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqFragCoord:
            case EvqPointCoord:
            case EvqFrontFacing:
                return true;
            default:
                break;
        }
        return false;
    }
    
    bool IsOutputESSL(ShShaderOutput output)
    {
        return output == SH_ESSL_OUTPUT;
    }
    
    bool IsOutputGLSL(ShShaderOutput output)
    {
        switch (output)
        {
            case SH_GLSL_130_OUTPUT:
            case SH_GLSL_140_OUTPUT:
            case SH_GLSL_150_CORE_OUTPUT:
            case SH_GLSL_330_CORE_OUTPUT:
            case SH_GLSL_400_CORE_OUTPUT:
            case SH_GLSL_410_CORE_OUTPUT:
            case SH_GLSL_420_CORE_OUTPUT:
            case SH_GLSL_430_CORE_OUTPUT:
            case SH_GLSL_440_CORE_OUTPUT:
            case SH_GLSL_450_CORE_OUTPUT:
            case SH_GLSL_COMPATIBILITY_OUTPUT:
                return true;
            default:
                break;
        }
        return false;
    }
    bool IsOutputHLSL(ShShaderOutput output)
    {
        switch (output)
        {
            case SH_HLSL_3_0_OUTPUT:
            case SH_HLSL_4_1_OUTPUT:
            case SH_HLSL_4_0_FL9_3_OUTPUT:
                return true;
            default:
                break;
        }
        return false;
    }
    bool IsOutputVulkan(ShShaderOutput output)
    {
        return output == SH_GLSL_VULKAN_OUTPUT;
    }
    
    bool IsInShaderStorageBlock(TIntermTyped *node)
    {
        TIntermBinary *binaryNode   = nullptr;
        TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
        if (swizzleNode)
        {
            binaryNode = swizzleNode->getOperand()->getAsBinaryNode();
            if (binaryNode)
            {
                return IsInShaderStorageBlock(binaryNode->getLeft());
            }
            TIntermSymbol *symbolNode = swizzleNode->getOperand()->getAsSymbolNode();
            if (symbolNode)
            {
                return symbolNode->getQualifier() == EvqBuffer;
            }
        }
        binaryNode = node->getAsBinaryNode();
    
        if (binaryNode)
        {
            return IsInShaderStorageBlock(binaryNode->getLeft());
        }
    
        const TType &type = node->getType();
    
        return type.getQualifier() == EvqBuffer;
    }
    
    }  // namespace sh