| // |
| // Copyright 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; |
| case EbtSamplerVideoWEBGL: |
| return GL_SAMPLER_VIDEO_IMAGE_WEBGL; |
| 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: |
| // Desktop specs do not use precision |
| return GL_NONE; |
| 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: |
| // Desktop specs do not use precision |
| return GL_NONE; |
| 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 TSpan<const 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: |
| case EvqHelperInvocation: |
| return true; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| bool IsShaderOutput(TQualifier qualifier) |
| { |
| return IsVaryingOut(qualifier) || IsBuiltinOutputVariable(qualifier); |
| } |
| |
| 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 IsOutputMetal(ShShaderOutput output) |
| { |
| return output == SH_GLSL_METAL_OUTPUT; |
| } |
| |
| bool IsInShaderStorageBlock(TIntermTyped *node) |
| { |
| TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); |
| if (swizzleNode) |
| { |
| return IsInShaderStorageBlock(swizzleNode->getOperand()); |
| } |
| |
| TIntermBinary *binaryNode = node->getAsBinaryNode(); |
| if (binaryNode) |
| { |
| switch (binaryNode->getOp()) |
| { |
| case EOpIndexDirectInterfaceBlock: |
| case EOpIndexIndirect: |
| case EOpIndexDirect: |
| case EOpIndexDirectStruct: |
| return IsInShaderStorageBlock(binaryNode->getLeft()); |
| default: |
| return false; |
| } |
| } |
| |
| const TType &type = node->getType(); |
| return type.getQualifier() == EvqBuffer; |
| } |
| |
| GLenum GetImageInternalFormatType(TLayoutImageInternalFormat iifq) |
| { |
| switch (iifq) |
| { |
| case EiifRGBA32F: |
| return GL_RGBA32F; |
| case EiifRGBA16F: |
| return GL_RGBA16F; |
| case EiifR32F: |
| return GL_R32F; |
| case EiifRGBA32UI: |
| return GL_RGBA32UI; |
| case EiifRGBA16UI: |
| return GL_RGBA16UI; |
| case EiifRGBA8UI: |
| return GL_RGBA8UI; |
| case EiifR32UI: |
| return GL_R32UI; |
| case EiifRGBA32I: |
| return GL_RGBA32I; |
| case EiifRGBA16I: |
| return GL_RGBA16I; |
| case EiifRGBA8I: |
| return GL_RGBA8I; |
| case EiifR32I: |
| return GL_R32I; |
| case EiifRGBA8: |
| return GL_RGBA8; |
| case EiifRGBA8_SNORM: |
| return GL_RGBA8_SNORM; |
| default: |
| return GL_NONE; |
| } |
| } |
| |
| bool IsSpecWithFunctionBodyNewScope(ShShaderSpec shaderSpec, int shaderVersion) |
| { |
| return (shaderVersion == 100 && !sh::IsWebGLBasedSpec(shaderSpec)); |
| } |
| |
| ImplicitTypeConversion GetConversion(TBasicType t1, TBasicType t2) |
| { |
| if (t1 == t2) |
| return ImplicitTypeConversion::Same; |
| |
| switch (t1) |
| { |
| case EbtInt: |
| switch (t2) |
| { |
| case EbtInt: |
| UNREACHABLE(); |
| break; |
| case EbtUInt: |
| return ImplicitTypeConversion::Invalid; |
| case EbtFloat: |
| return ImplicitTypeConversion::Left; |
| default: |
| return ImplicitTypeConversion::Invalid; |
| } |
| break; |
| case EbtUInt: |
| switch (t2) |
| { |
| case EbtInt: |
| return ImplicitTypeConversion::Invalid; |
| case EbtUInt: |
| UNREACHABLE(); |
| break; |
| case EbtFloat: |
| return ImplicitTypeConversion::Left; |
| default: |
| return ImplicitTypeConversion::Invalid; |
| } |
| break; |
| case EbtFloat: |
| switch (t2) |
| { |
| case EbtInt: |
| case EbtUInt: |
| return ImplicitTypeConversion::Right; |
| case EbtFloat: |
| UNREACHABLE(); |
| break; |
| default: |
| return ImplicitTypeConversion::Invalid; |
| } |
| break; |
| default: |
| return ImplicitTypeConversion::Invalid; |
| } |
| return ImplicitTypeConversion::Invalid; |
| } |
| |
| bool IsValidImplicitConversion(sh::ImplicitTypeConversion conversion, TOperator op) |
| { |
| switch (conversion) |
| { |
| case sh::ImplicitTypeConversion::Same: |
| return true; |
| case sh::ImplicitTypeConversion::Left: |
| switch (op) |
| { |
| case EOpEqual: |
| case EOpNotEqual: |
| case EOpLessThan: |
| case EOpGreaterThan: |
| case EOpLessThanEqual: |
| case EOpGreaterThanEqual: |
| case EOpAdd: |
| case EOpSub: |
| case EOpMul: |
| case EOpDiv: |
| return true; |
| default: |
| break; |
| } |
| break; |
| case sh::ImplicitTypeConversion::Right: |
| switch (op) |
| { |
| case EOpAssign: |
| case EOpInitialize: |
| case EOpEqual: |
| case EOpNotEqual: |
| case EOpLessThan: |
| case EOpGreaterThan: |
| case EOpLessThanEqual: |
| case EOpGreaterThanEqual: |
| case EOpAdd: |
| case EOpSub: |
| case EOpMul: |
| case EOpDiv: |
| case EOpAddAssign: |
| case EOpSubAssign: |
| case EOpMulAssign: |
| case EOpDivAssign: |
| return true; |
| default: |
| break; |
| } |
| break; |
| case sh::ImplicitTypeConversion::Invalid: |
| break; |
| } |
| return false; |
| } |
| |
| } // namespace sh |