Imported a few ES3 fixes from Angle Imported some of the more trivial bug fixes: - Added a few missing interface block cases - Added checks for varying structs - Added checks for unsized arrays - Added first-class array check for pre ES3 compilation - Added check that ES3 functions do not use builtin names (ES3 only) - Added more binary operator checks Change-Id: I3d75453f17e1123478ef7da0998e869970a7fb7d Reviewed-on: https://swiftshader-review.googlesource.com/8289 Tested-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp index dbbfb19..a6b1b82 100644 --- a/src/OpenGL/compiler/Intermediate.cpp +++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -62,6 +62,134 @@ } } +TOperator TypeToConstructorOperator(const TType &type) +{ + switch(type.getBasicType()) + { + case EbtFloat: + if(type.isMatrix()) + { + switch(type.getNominalSize()) + { + case 2: + switch(type.getSecondarySize()) + { + case 2: + return EOpConstructMat2; + case 3: + return EOpConstructMat2x3; + case 4: + return EOpConstructMat2x4; + default: + break; + } + break; + + case 3: + switch(type.getSecondarySize()) + { + case 2: + return EOpConstructMat3x2; + case 3: + return EOpConstructMat3; + case 4: + return EOpConstructMat3x4; + default: + break; + } + break; + + case 4: + switch(type.getSecondarySize()) + { + 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; +} + const char* getOperatorString(TOperator op) { switch (op) { case EOpInitialize: return "="; @@ -657,6 +785,17 @@ // //////////////////////////////////////////////////////////////// +// static +TIntermTyped *TIntermTyped::CreateIndexNode(int index) +{ + ConstantUnion *u = new ConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConstExpr, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + // // Say whether or not an operation node changes the value of a variable. //
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp index 7bd7e64..83f58ce 100644 --- a/src/OpenGL/compiler/ParseHelper.cpp +++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -28,6 +28,77 @@ // //////////////////////////////////////////////////////////////////////// +namespace +{ + 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); + } + + bool IsAssignment(TOperator op) + { + switch(op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + return true; + default: + return false; + } + } +} + // // Look at a '.' field selector string and change it into offsets // for a vector. @@ -282,6 +353,7 @@ case EOpIndexDirect: case EOpIndexIndirect: case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return lValueErrorCheck(line, op, binaryNode->getLeft()); case EOpVectorSwizzle: errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); @@ -756,7 +828,7 @@ if (IsSampler(type.getBasicType())) return true; - if (type.getBasicType() == EbtStruct) { + if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { const TFieldList& fields = type.getStruct()->fields(); for(unsigned int i = 0; i < fields.size(); ++i) { if (containsSampler(*fields[i]->type())) @@ -776,7 +848,7 @@ { TIntermConstantUnion* constant = expr->getAsConstantUnion(); - if (constant == 0 || !constant->isScalarInt()) + if (expr->getQualifier() != EvqConstExpr || constant == 0 || !constant->isScalarInt()) { error(line, "array size must be a constant integer expression", ""); return true; @@ -798,14 +870,20 @@ { size = constant->getIConst(0); - if (size <= 0) + if (size < 0) { - error(line, "array size must be a positive integer", ""); + error(line, "array size must be non-negative", ""); size = 1; return true; } } + if(size == 0) + { + error(line, "array size must be greater than zero", ""); + return true; + } + return false; } @@ -839,6 +917,15 @@ return true; } + // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. + // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section 4.3.4). + if(mShaderVersion >= 300 && type.type == EbtStruct && IsVarying(type.qualifier)) + { + error(line, "cannot declare arrays of structs of this qualifier", + TType(type).getCompleteString().c_str()); + return true; + } + return false; } @@ -1191,9 +1278,19 @@ ASSERT(intermNode != nullptr); TType type = TType(pType); - if(type.isArray() && (type.getArraySize() == 0)) + if(type.isUnsizedArray()) { - type.setArraySize(initializer->getArraySize()); + // We have not checked yet whether the initializer actually is an array or not. + if(initializer->isArray()) + { + type.setArraySize(initializer->getArraySize()); + } + else + { + // Having a non-array initializer for an unsized array will result in an error later, + // so we don't generate an error message here. + type.setArraySize(1u); + } } TVariable *variable = nullptr; @@ -1285,6 +1382,12 @@ if(mShaderVersion < 300) { + if(typeSpecifier.array) + { + error(typeSpecifier.line, "not supported", "first-class array"); + returnType.clearArrayness(); + } + if(qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) { error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); @@ -1300,44 +1403,87 @@ } else { - switch(qualifier) + if(!returnType.layoutQualifier.isEmpty()) { - case EvqSmoothIn: - case EvqSmoothOut: - case EvqVertexOut: - case EvqFragmentIn: - case EvqCentroidOut: - case EvqCentroidIn: - if(typeSpecifier.type == EbtBool) - { - error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); - recover(); - } - if(typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt) - { - error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier)); - recover(); - } - break; + globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout"); + } - case EvqVertexIn: - case EvqFragmentOut: - case EvqFlatIn: - case EvqFlatOut: - if(typeSpecifier.type == EbtBool) - { - error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); - recover(); - } - break; - - default: break; + if(IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || returnType.qualifier == EvqFragmentOut) + { + checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, typeSpecifier.line); } } return returnType; } +void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation) +{ + // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. + if(type.type == EbtBool) + { + error(qualifierLocation, "cannot be bool", getQualifierString(qualifier)); + } + + // Specific restrictions apply for vertex shader inputs and fragment shader outputs. + switch(qualifier) + { + case EvqVertexIn: + // ESSL 3.00 section 4.3.4 + if(type.array) + { + error(qualifierLocation, "cannot be array", getQualifierString(qualifier)); + } + // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck + return; + case EvqFragmentOut: + // ESSL 3.00 section 4.3.6 + if(type.isMatrix()) + { + error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier)); + } + // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck + return; + default: + break; + } + + // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of + // restrictions. + bool typeContainsIntegers = (type.type == EbtInt || type.type == EbtUInt || + type.isStructureContainingType(EbtInt) || + type.isStructureContainingType(EbtUInt)); + if(typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) + { + error(qualifierLocation, "must use 'flat' interpolation here", getQualifierString(qualifier)); + } + + if(type.type == EbtStruct) + { + // ESSL 3.00 sections 4.3.4 and 4.3.6. + // These restrictions are only implied by the ESSL 3.00 spec, but + // the ESSL 3.10 spec lists these restrictions explicitly. + if(type.array) + { + error(qualifierLocation, "cannot be an array of structures", getQualifierString(qualifier)); + } + if(type.isStructureContainingArrays()) + { + error(qualifierLocation, "cannot be a structure containing an array", getQualifierString(qualifier)); + } + if(type.isStructureContainingType(EbtStruct)) + { + error(qualifierLocation, "cannot be a structure containing a structure", getQualifierString(qualifier)); + } + if(type.isStructureContainingType(EbtBool)) + { + error(qualifierLocation, "cannot be a structure containing a bool", getQualifierString(qualifier)); + } + } +} + TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc &identifierOrTypeLocation, const TString &identifier) @@ -1915,7 +2061,13 @@ // here. // TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion())); - if(prevDec) + if(getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str())) + { + // With ESSL 3.00, names of built-in functions cannot be redeclared as functions. + // Therefore overloading or redefining builtin functions is an error. + error(location, "Name of a built-in function cannot be redeclared as function", function->getName().c_str()); + } + else if(prevDec) { if(prevDec->getReturnType() != function->getReturnType()) { @@ -1969,84 +2121,7 @@ } else { - switch(publicType.type) - { - case EbtFloat: - if(publicType.isMatrix()) - { - switch(publicType.getCols()) - { - case 2: - switch(publicType.getRows()) - { - case 2: op = EOpConstructMat2; break; - case 3: op = EOpConstructMat2x3; break; - case 4: op = EOpConstructMat2x4; break; - } - break; - case 3: - switch(publicType.getRows()) - { - case 2: op = EOpConstructMat3x2; break; - case 3: op = EOpConstructMat3; break; - case 4: op = EOpConstructMat3x4; break; - } - break; - case 4: - switch(publicType.getRows()) - { - case 2: op = EOpConstructMat4x2; break; - case 3: op = EOpConstructMat4x3; break; - case 4: op = EOpConstructMat4; break; - } - break; - } - } - else - { - switch(publicType.getNominalSize()) - { - case 1: op = EOpConstructFloat; break; - case 2: op = EOpConstructVec2; break; - case 3: op = EOpConstructVec3; break; - case 4: op = EOpConstructVec4; break; - } - } - break; - - case EbtInt: - switch(publicType.getNominalSize()) - { - case 1: op = EOpConstructInt; break; - case 2: op = EOpConstructIVec2; break; - case 3: op = EOpConstructIVec3; break; - case 4: op = EOpConstructIVec4; break; - } - break; - - case EbtUInt: - switch(publicType.getNominalSize()) - { - case 1: op = EOpConstructUInt; break; - case 2: op = EOpConstructUVec2; break; - case 3: op = EOpConstructUVec3; break; - case 4: op = EOpConstructUVec4; break; - } - break; - - case EbtBool: - switch(publicType.getNominalSize()) - { - case 1: op = EOpConstructBool; break; - case 2: op = EOpConstructBVec2; break; - case 3: op = EOpConstructBVec3; break; - case 4: op = EOpConstructBVec4; break; - } - break; - - default: break; - } - + op = TypeToConstructorOperator(TType(publicType)); if(op == EOpNull) { error(publicType.line, "cannot construct this type", getBasicString(publicType.type)); @@ -2717,9 +2792,8 @@ } else { - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped *index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); + TIntermTyped *index = TIntermTyped::CreateIndexNode(i); + index->setLine(fieldLocation); indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation); indexedExpression->setType(*fields[i]->type()); } @@ -3237,6 +3311,46 @@ { return false; } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + if((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) + { + return false; + } + + // Are the sizes compatible? + if(left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize()) + { + // If the nominal sizes of operands do not match: + // One of them must be a scalar. + if(!left->isScalar() && !right->isScalar()) + return false; + + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if(!right->isScalar() && (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) + return false; + } + break; default: break; }
diff --git a/src/OpenGL/compiler/ParseHelper.h b/src/OpenGL/compiler/ParseHelper.h index 8733ef5..ea613eb 100644 --- a/src/OpenGL/compiler/ParseHelper.h +++ b/src/OpenGL/compiler/ParseHelper.h
@@ -142,6 +142,7 @@ bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier); bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *); void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation); + void checkInputOutputTypeIsValidES3(const TQualifier qualifier, const TPublicType &type, const TSourceLoc &qualifierLocation); const TExtensionBehavior& extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); } bool supportsExtension(const char* extension);
diff --git a/src/OpenGL/compiler/SymbolTable.cpp b/src/OpenGL/compiler/SymbolTable.cpp index 39023ae..004a1d7 100644 --- a/src/OpenGL/compiler/SymbolTable.cpp +++ b/src/OpenGL/compiler/SymbolTable.cpp
@@ -121,6 +121,17 @@ return false; } +bool TStructure::containsType(TBasicType type) const +{ + for(size_t i = 0; i < mFields->size(); ++i) + { + const TType *fieldType = (*mFields)[i]->type(); + if(fieldType->getBasicType() == type || fieldType->isStructureContainingType(type)) + return true; + } + return false; +} + bool TStructure::containsSamplers() const { for(size_t i = 0; i < mFields->size(); ++i)
diff --git a/src/OpenGL/compiler/SymbolTable.h b/src/OpenGL/compiler/SymbolTable.h index d8c6029..c4fdbfe 100644 --- a/src/OpenGL/compiler/SymbolTable.h +++ b/src/OpenGL/compiler/SymbolTable.h
@@ -369,6 +369,7 @@ { if(ptype1->getBasicType() == EbtGSampler2D) { + insertUnmangledBuiltIn(name); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5); @@ -376,6 +377,7 @@ } else if(ptype1->getBasicType() == EbtGSampler3D) { + insertUnmangledBuiltIn(name); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5); @@ -383,6 +385,7 @@ } else if(ptype1->getBasicType() == EbtGSamplerCube) { + insertUnmangledBuiltIn(name); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5); @@ -390,6 +393,7 @@ } else if(ptype1->getBasicType() == EbtGSampler2DArray) { + insertUnmangledBuiltIn(name); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); @@ -398,6 +402,7 @@ else if(IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3)) { ASSERT(!ptype4); + insertUnmangledBuiltIn(name); insertBuiltIn(level, op, ext, GenType(rvalue, 1), name, GenType(ptype1, 1), GenType(ptype2, 1), GenType(ptype3, 1)); insertBuiltIn(level, op, ext, GenType(rvalue, 2), name, GenType(ptype1, 2), GenType(ptype2, 2), GenType(ptype3, 2)); insertBuiltIn(level, op, ext, GenType(rvalue, 3), name, GenType(ptype1, 3), GenType(ptype2, 3), GenType(ptype3, 3)); @@ -406,6 +411,7 @@ else if(IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3)) { ASSERT(!ptype4); + insertUnmangledBuiltIn(name); insertBuiltIn(level, op, ext, VecType(rvalue, 2), name, VecType(ptype1, 2), VecType(ptype2, 2), VecType(ptype3, 2)); insertBuiltIn(level, op, ext, VecType(rvalue, 3), name, VecType(ptype1, 3), VecType(ptype2, 3), VecType(ptype3, 3)); insertBuiltIn(level, op, ext, VecType(rvalue, 4), name, VecType(ptype1, 4), VecType(ptype2, 4), VecType(ptype3, 4)); @@ -441,17 +447,20 @@ function->addParameter(param5); } + ASSERT(hasUnmangledBuiltIn(name)); insert(level, *function); } } void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) { + insertUnmangledBuiltIn(name); insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); } void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) { + insertUnmangledBuiltIn(name); insertBuiltIn(level, EOpNull, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); } @@ -518,6 +527,12 @@ void setGlobalInvariant() { mGlobalInvariant = true; } bool getGlobalInvariant() const { return mGlobalInvariant; } + bool hasUnmangledBuiltIn(const char *name) { return mUnmangledBuiltinNames.count(std::string(name)) > 0; } + +private: + // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00. + void insertUnmangledBuiltIn(const char *name) { mUnmangledBuiltinNames.insert(std::string(name)); } + protected: ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); } @@ -525,6 +540,8 @@ typedef std::map< TBasicType, TPrecision > PrecisionStackLevel; std::vector< PrecisionStackLevel > precisionStack; + std::set<std::string> mUnmangledBuiltinNames; + std::set<std::string> mInvariantVaryings; bool mGlobalInvariant; };
diff --git a/src/OpenGL/compiler/Types.h b/src/OpenGL/compiler/Types.h index f24f9e6..d4d98d0 100644 --- a/src/OpenGL/compiler/Types.h +++ b/src/OpenGL/compiler/Types.h
@@ -132,6 +132,7 @@ return mDeepestNesting; } bool containsArrays() const; + bool containsType(TBasicType type) const; bool containsSamplers() const; bool equals(const TStructure &other) const; @@ -381,6 +382,7 @@ int getSecondarySize() const { return secondarySize; } bool isArray() const { return array ? true : false; } + bool isUnsizedArray() const { return array && arraySize == 0; } int getArraySize() const { return arraySize; } void setArraySize(int s) { array = true; arraySize = s; } int getMaxArraySize () const { return maxArraySize; } @@ -468,6 +470,11 @@ return structure ? structure->containsArrays() : false; } + bool isStructureContainingType(TBasicType t) const + { + return structure ? structure->containsType(t) : false; + } + bool isStructureContainingSamplers() const { return structure ? structure->containsSamplers() : false; @@ -576,6 +583,16 @@ return userDef->isStructureContainingArrays(); } + bool isStructureContainingType(TBasicType t) const + { + if(!userDef) + { + return false; + } + + return userDef->isStructureContainingType(t); + } + bool isMatrix() const { return primarySize > 1 && secondarySize > 1;
diff --git a/src/OpenGL/compiler/intermediate.h b/src/OpenGL/compiler/intermediate.h index 740fb71..7757d89 100644 --- a/src/OpenGL/compiler/intermediate.h +++ b/src/OpenGL/compiler/intermediate.h
@@ -238,6 +238,7 @@ EOpBitwiseOrAssign }; +extern TOperator TypeToConstructorOperator(const TType &type); extern const char* getOperatorString(TOperator op); class TIntermTraverser; @@ -334,6 +335,7 @@ int registerSize() const { return type.registerSize(); } int getArraySize() const { return type.getArraySize(); } + static TIntermTyped *CreateIndexNode(int index); protected: TType type; };