| // | |
| // 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; | |
| 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 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: | |
| 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 |