bool ValidateLimitations::validateIndexing(TIntermBinary* node) { ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect)); bool valid = true; TIntermTyped* index = node->getRight(); // The index expression must have integral type. if (!index->isScalar() || (index->getBasicType() != EbtInt)) { error(index->getLine(), "Index expression must have integral type", index->getCompleteString().c_str()); valid = false; } // The index expession must be a constant-index-expression unless // the operand is a uniform in a vertex shader. TIntermTyped* operand = node->getLeft(); bool skip = (mShaderType == SH_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform); if (!skip && !isConstIndexExpr(index)) { error(index->getLine(), "Index expression must be constant", "[]"); valid = false; } return valid; }
void TIntermAggregate::setBuiltInFunctionPrecision() { // All built-ins returning bool should be handled as ops, not functions. ASSERT(getBasicType() != EbtBool); TPrecision precision = EbpUndefined; TIntermSequence::iterator childIter = mSequence.begin(); while (childIter != mSequence.end()) { TIntermTyped *typed = (*childIter)->getAsTyped(); // ESSL spec section 8: texture functions get their precision from the sampler. if (typed && IsSampler(typed->getBasicType())) { precision = typed->getPrecision(); break; } ++childIter; } // ESSL 3.0 spec section 8: textureSize always gets highp precision. // All other functions that take a sampler are assumed to be texture functions. if (mName.find("textureSize") == 0) mType.setPrecision(EbpHigh); else mType.setPrecision(precision); }
bool IntermNodePatternMatcher::match(TIntermDeclaration *node) { if ((mMask & kMultiDeclaration) != 0) { if (node->getSequence()->size() > 1) { return true; } } if ((mMask & kArrayDeclaration) != 0) { if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays()) { return true; } // Need to check from all declarators whether they are arrays since that may vary between // declarators. for (TIntermNode *declarator : *node->getSequence()) { if (declarator->getAsTyped()->isArray()) { return true; } } } if ((mMask & kNamelessStructDeclaration) != 0) { TIntermTyped *declarator = node->getSequence()->front()->getAsTyped(); if (declarator->getBasicType() == EbtStruct && declarator->getType().getStruct()->name() == "") { return true; } } return false; }
// // Make sure there is enough data provided to the constructor to build // something of the type of the constructor. Also returns the type of // the constructor. // // Returns true if there was an error in construction. // bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type) { *type = function.getReturnType(); bool constructingMatrix = false; switch(op) { case EOpConstructMat2: case EOpConstructMat3: case EOpConstructMat4: constructingMatrix = true; break; default: break; } // // Note: It's okay to have too many components available, but not okay to have unused // arguments. 'full' will go to true when enough args have been seen. If we loop // again, there is an extra argument, so 'overfull' will become true. // int size = 0; bool constType = true; bool full = false; bool overFull = false; bool matrixInMatrix = false; bool arrayArg = false; for (int i = 0; i < function.getParamCount(); ++i) { const TParameter& param = function.getParam(i); size += param.type->getObjectSize(); if (constructingMatrix && param.type->isMatrix()) matrixInMatrix = true; if (full) overFull = true; if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) full = true; if (param.type->getQualifier() != EvqConst) constType = false; if (param.type->isArray()) arrayArg = true; } if (constType) type->setQualifier(EvqConst); if (type->isArray() && type->getArraySize() != function.getParamCount()) { error(line, "array constructor needs one argument per array element", "constructor", ""); return true; } if (arrayArg && op != EOpConstructStruct) { error(line, "constructing from a non-dereferenced array", "constructor", ""); return true; } if (matrixInMatrix && !type->isArray()) { if (function.getParamCount() != 1) { error(line, "constructing matrix from matrix can only take one argument", "constructor", ""); return true; } } if (overFull) { error(line, "too many arguments", "constructor", ""); return true; } if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) { error(line, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); return true; } if (!type->isMatrix() || !matrixInMatrix) { if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || (op == EOpConstructStruct && size < type->getObjectSize())) { error(line, "not enough data provided for construction", "constructor", ""); return true; } } TIntermTyped *typed = node ? node->getAsTyped() : 0; if (typed == 0) { error(line, "constructor argument does not have a type", "constructor", ""); return true; } if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { error(line, "cannot convert a sampler", "constructor", ""); return true; } if (typed->getBasicType() == EbtVoid) { error(line, "cannot convert a void", "constructor", ""); return true; } return false; }
bool TSamplerTraverser::traverseAggregate( bool preVisit, TIntermAggregate *node, TIntermTraverser *it) { TSamplerTraverser* sit = static_cast<TSamplerTraverser*>(it); TInfoSink &infoSink = sit->infoSink; if (sit->abort) return false; if (! (sit->typing) ) { switch (node->getOp()) { case EOpFunction: // Store the current function name to use to setup the parameters sit->currentFunction = node->getName().c_str(); break; case EOpParameters: // Store the parameters to the function in the map sit->functionMap[sit->currentFunction.c_str()] = &(node->getSequence()); break; case EOpFunctionCall: { // This is a bit tricky. Find the function in the map. Loop over the parameters // and see if the parameters have been marked as a typed sampler. If so, propagate // the sampler type to the caller if ( sit->functionMap.find ( node->getName().c_str() ) != sit->functionMap.end() ) { // Get the sequence of function parameters TIntermSequence *funcSequence = sit->functionMap[node->getName().c_str()]; // Get the sequence of parameters being passed to function TIntermSequence &sequence = node->getSequence(); // Grab iterators to both sequences TIntermSequence::iterator it = sequence.begin(); TIntermSequence::iterator funcIt = funcSequence->begin(); assert ( sequence.size() == funcSequence->size() ); if ( sequence.size() == funcSequence->size() ) { while ( it != sequence.end() ) { TIntermSymbol *sym = (*it)->getAsSymbolNode(); TIntermSymbol *funcSym = (*funcIt)->getAsSymbolNode(); if ( sym != NULL && funcSym != NULL) { // If the parameter is generic, and the sampler to which // it is being passed has been marked, propogate its sampler // type to the caller. if ( sym->getBasicType() == EbtSamplerGeneric && funcSym->getBasicType() != EbtSamplerGeneric ) { sit->typeSampler ( sym, funcSym->getBasicType() ); } } it++; funcIt++; } } } } break; //HLSL texture functions case EOpTex1D: case EOpTex1DProj: case EOpTex1DLod: case EOpTex1DBias: case EOpTex1DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler1D); } else if (sampArg->getBasicType() != EbtSampler1D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTex2D: case EOpTex2DProj: case EOpTex2DLod: case EOpTex2DBias: case EOpTex2DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler2D); } else if (sampArg->getBasicType() != EbtSampler2D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTexRect: case EOpTexRectProj: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSamplerRect); } else if (sampArg->getBasicType() != EbtSamplerRect) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTex3D: case EOpTex3DProj: case EOpTex3DLod: case EOpTex3DBias: case EOpTex3DGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSampler3D); } else if (sampArg->getBasicType() != EbtSampler3D) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; case EOpTexCube: case EOpTexCubeProj: case EOpTexCubeLod: case EOpTexCubeBias: case EOpTexCubeGrad: { TIntermSequence &sequence = node->getSequence(); assert( sequence.size()); TIntermTyped *sampArg = sequence[0]->getAsTyped(); if ( sampArg) { if (sampArg->getBasicType() == EbtSamplerGeneric) { //type the sampler sit->typeSampler( sampArg, EbtSamplerCube); } else if (sampArg->getBasicType() != EbtSamplerCube) { //We have a sampler mismatch error infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n"; } } else { assert(0); } } // We need to continue the traverse here, because the calls could be nested break; default: break; } } return !(sit->abort); }