// // 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 #include "compiler/preprocessor/numeric_lex.h" #include "compiler/translator/SymbolTable.h" #include "common/utilities.h" bool strtof_clamp(const std::string &str, float *value) { bool success = pp::numeric_lex_float(str, value); if (!success) *value = std::numeric_limits::max(); return success; } bool atoi_clamp(const char *str, unsigned int *value) { bool success = pp::numeric_lex_int(str, value); if (!success) *value = std::numeric_limits::max(); return success; } namespace sh { GLenum GLVariableType(const TType &type) { if (type.getBasicType() == EbtFloat) { if (type.isScalar()) { return GL_FLOAT; } else 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(); } } 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(); } 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(); } 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(); } default: UNREACHABLE(); } } else UNREACHABLE(); } else if (type.getBasicType() == EbtInt) { if (type.isScalar()) { return GL_INT; } else 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(); } } else UNREACHABLE(); } else if (type.getBasicType() == EbtUInt) { if (type.isScalar()) { return GL_UNSIGNED_INT; } else 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(); } } else UNREACHABLE(); } else if (type.getBasicType() == EbtBool) { if (type.isScalar()) { return GL_BOOL; } else 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(); } } else UNREACHABLE(); } 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 EbtSampler2DRect: return GL_SAMPLER_2D_RECT_ARB; case EbtSampler2DArray: return GL_SAMPLER_2D_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 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 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; 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; } TString ArrayString(const TType &type) { if (!type.isArray()) { return ""; } return "[" + str(type.getArraySize()) + "]"; } bool IsVaryingOut(TQualifier qualifier) { switch (qualifier) { case EvqVaryingOut: case EvqSmoothOut: case EvqFlatOut: case EvqCentroidOut: case EvqVertexOut: return true; default: break; } return false; } bool IsVaryingIn(TQualifier qualifier) { switch (qualifier) { case EvqVaryingIn: case EvqSmoothIn: case EvqFlatIn: case EvqCentroidIn: case EvqFragmentIn: return true; default: break; } return false; } bool IsVarying(TQualifier qualifier) { return IsVaryingIn(qualifier) || IsVaryingOut(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: return INTERPOLATION_SMOOTH; case EvqCentroidIn: case EvqCentroidOut: return INTERPOLATION_CENTROID; default: UNREACHABLE(); return INTERPOLATION_SMOOTH; } } 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(); return TType(); } } TOperator TypeToConstructorOperator(const TType &type) { switch (type.getBasicType()) { case EbtFloat: if (type.isMatrix()) { switch (type.getCols()) { case 2: switch (type.getRows()) { case 2: return EOpConstructMat2; case 3: return EOpConstructMat2x3; case 4: return EOpConstructMat2x4; default: break; } break; case 3: switch (type.getRows()) { case 2: return EOpConstructMat3x2; case 3: return EOpConstructMat3; case 4: return EOpConstructMat3x4; default: break; } break; case 4: switch (type.getRows()) { case 2: return EOpConstructMat4x2; case 3: return EOpConstructMat4x3; case 4: return EOpConstructMat4; default: break; } break; } } else { switch (type.getNominalSize()) { case 1: return EOpConstructFloat; case 2: return EOpConstructVec2; case 3: return EOpConstructVec3; case 4: return EOpConstructVec4; default: break; } } break; case EbtInt: switch (type.getNominalSize()) { case 1: return EOpConstructInt; case 2: return EOpConstructIVec2; case 3: return EOpConstructIVec3; case 4: return EOpConstructIVec4; default: break; } break; case EbtUInt: switch (type.getNominalSize()) { case 1: return EOpConstructUInt; case 2: return EOpConstructUVec2; case 3: return EOpConstructUVec3; case 4: return EOpConstructUVec4; default: break; } break; case EbtBool: switch (type.getNominalSize()) { case 1: return EOpConstructBool; case 2: return EOpConstructBVec2; case 3: return EOpConstructBVec3; case 4: return EOpConstructBVec4; default: break; } break; case EbtStruct: return EOpConstructStruct; default: break; } return EOpNull; } GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable) : mSymbolTable(symbolTable) { } template void GetVariableTraverser::setTypeSpecificInfo( const TType &type, const TString& name, InterfaceBlockField *variable); template void GetVariableTraverser::setTypeSpecificInfo( const TType &type, const TString& name, ShaderVariable *variable); template void GetVariableTraverser::setTypeSpecificInfo( const TType &type, const TString& name, Uniform *variable); template<> void GetVariableTraverser::setTypeSpecificInfo( const TType &type, const TString& name, Varying *variable) { ASSERT(variable); switch (type.getQualifier()) { case EvqVaryingIn: case EvqVaryingOut: case EvqVertexOut: case EvqSmoothOut: case EvqFlatOut: case EvqCentroidOut: if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant()) { variable->isInvariant = true; } break; default: break; } variable->interpolation = GetInterpolationType(type.getQualifier()); } template void GetVariableTraverser::traverse(const TType &type, const TString &name, std::vector *output) { const TStructure *structure = type.getStruct(); VarT variable; variable.name = name.c_str(); variable.arraySize = type.getArraySize(); if (!structure) { variable.type = GLVariableType(type); variable.precision = GLVariablePrecision(type); } else { // Note: this enum value is not exposed outside ANGLE variable.type = GL_STRUCT_ANGLEX; variable.structName = structure->name().c_str(); const TFieldList &fields = structure->fields(); for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) { TField *field = fields[fieldIndex]; traverse(*field->type(), field->name(), &variable.fields); } } setTypeSpecificInfo(type, name, &variable); visitVariable(&variable); ASSERT(output); output->push_back(variable); } template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); // 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; } } // namespace sh