Enforce fragment precision qualifier requirement

TRAC #12156 The fragment shader has no default precision qualifier for floating-point types, so compilation should fail when it's not set explicitly globally or per declaration. Signed-off-by: Shannon Woods Signed-off-by: Daniel Koch Author: Nicolas Capens git-svn-id: https://angleproject.googlecode.com/svn/trunk@293 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 0578f81c
......@@ -12,9 +12,11 @@
//
enum TPrecision
{
EbpHigh,
EbpMedium,
// These need to be kept sorted
EbpUndefined,
EbpLow,
EbpMedium,
EbpHigh,
};
__inline const char* getPrecisionString(TPrecision p)
......@@ -24,7 +26,7 @@ __inline const char* getPrecisionString(TPrecision p)
case EbpHigh: return "highp"; break;
case EbpMedium: return "mediump"; break;
case EbpLow: return "lowp"; break;
default: return "unknown precision";
default: return "mediump"; break; // Safest fallback
}
}
......
......@@ -23,6 +23,8 @@ void TBuiltIns::initialize()
TString BuiltInFunctionsVertex;
TString BuiltInFunctionsFragment;
TString StandardUniforms;
TString VertexDefaultPrecision;
TString FragmentDefaultPrecision;
{
//============================================================================
......@@ -427,19 +429,47 @@ void TBuiltIns::initialize()
// Depth range in window coordinates
//
s.append(TString("struct gl_DepthRangeParameters {"));
s.append(TString(" float near;")); // n // FIXME: highp
s.append(TString(" float far;")); // f // FIXME: highp
s.append(TString(" float diff;")); // f - n // FIXME: highp
s.append(TString(" highp float near;")); // n
s.append(TString(" highp float far;")); // f
s.append(TString(" highp float diff;")); // f - n
s.append(TString("};"));
s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;"));
s.append(TString("\n"));
}
{
//============================================================================
//
// Default precision for vertex shaders.
//
//============================================================================
TString& s = VertexDefaultPrecision;
s.append(TString("precision highp int;"));
s.append(TString("precision highp float;"));
s.append(TString("\n"));
}
{
//============================================================================
//
// Default precision for fragment shaders.
//
//============================================================================
TString& s = FragmentDefaultPrecision;
s.append(TString("precision mediump int;"));
// No default precision for float in fragment shaders
s.append(TString("\n"));
}
builtInStrings[EShLangFragment].push_back(FragmentDefaultPrecision);
builtInStrings[EShLangFragment].push_back(BuiltInFunctions.c_str());
builtInStrings[EShLangFragment].push_back(BuiltInFunctionsFragment);
builtInStrings[EShLangFragment].push_back(StandardUniforms);
builtInStrings[EShLangVertex].push_back(VertexDefaultPrecision);
builtInStrings[EShLangVertex].push_back(BuiltInFunctions);
builtInStrings[EShLangVertex].push_back(BuiltInFunctionsVertex);
builtInStrings[EShLangVertex].push_back(StandardUniforms);
......@@ -489,18 +519,18 @@ void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable)
switch(language) {
case EShLangFragment: {
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EvqFragCoord, 4))); // FIXME: mediump
symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EvqFrontFacing, 1)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EvqFragColor, 4))); // FIXME: mediump
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EvqFragData, 4))); // FIXME: mediump
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EvqPointCoord, 2))); // FIXME: mediump
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
}
break;
case EShLangVertex:
symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EvqPosition, 4))); // FIXME: highp
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EvqPointSize, 1))); // FIXME: mediump
symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
break;
default: break;
}
......@@ -587,7 +617,7 @@ void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable, const TBu
case EShLangFragment: {
// Set up gl_FragData. The array size.
TType fragData(EbtFloat, EvqFragColor, 4, false, true);
TType fragData(EbtFloat, EbpMedium, EvqFragColor, 4, false, true);
fragData.setArraySize(resources.maxDrawBuffers);
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
}
......
......@@ -16,6 +16,15 @@
bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
TPrecision GetHighestPrecision( TPrecision left, TPrecision right, TInfoSink& infoSink ){
TPrecision highest = left > right ? left : right;
if (highest == EbpUndefined) {
infoSink.info.message(EPrefixInternalError, "Unknown or invalid precision for operands", 0);
}
return highest;
}
////////////////////////////////////////////////////////////////////////////
//
// First set of functions are to help build the intermediate representation.
......@@ -223,7 +232,8 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode,
}
if (newType != EbtVoid) {
child = addConversion(op, TType(newType, EvqTemporary, child->getNominalSize(),
child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
child->getNominalSize(),
child->isMatrix(),
child->isArray()),
child);
......@@ -420,7 +430,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
return 0;
}
TType type(promoteTo, EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
newNode = new TIntermUnary(newOp, type);
newNode->setLine(node->getLine());
newNode->setOperand(node);
......@@ -591,7 +601,7 @@ TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
for (int i = 0; i < fields.num; i++) {
unionArray = new ConstantUnion[1];
unionArray->setIConst(fields.offsets[i]);
constIntNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), line);
constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
sequenceVector.push_back(constIntNode);
}
......@@ -777,6 +787,9 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
//
setType(left->getType());
TPrecision highestPrecision = GetHighestPrecision(left->getPrecision(), right->getPrecision(), infoSink);
getTypePointer()->changePrecision(highestPrecision);
//
// Array operations.
//
......@@ -789,7 +802,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
//
case EOpEqual:
case EOpNotEqual:
setType(TType(EbtBool));
setType(TType(EbtBool, EbpUndefined));
break;
//
......@@ -824,7 +837,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
setType(TType(EbtBool));
setType(TType(EbtBool, EbpUndefined));
break;
//
......@@ -834,7 +847,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
case EOpLogicalOr:
if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
return false;
setType(TType(EbtBool));
setType(TType(EbtBool, EbpUndefined));
break;
//
......@@ -866,12 +879,12 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
op = EOpVectorTimesMatrix;
else {
op = EOpMatrixTimesScalar;
setType(TType(type, EvqTemporary, size, true));
setType(TType(type, highestPrecision, EvqTemporary, size, true));
}
} else if (left->isMatrix() && !right->isMatrix()) {
if (right->isVector()) {
op = EOpMatrixTimesVector;
setType(TType(type, EvqTemporary, size, false));
setType(TType(type, highestPrecision, EvqTemporary, size, false));
} else {
op = EOpMatrixTimesScalar;
}
......@@ -882,7 +895,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
// leave as component product
} else if (left->isVector() || right->isVector()) {
op = EOpVectorTimesScalar;
setType(TType(type, EvqTemporary, size, false));
setType(TType(type, highestPrecision, EvqTemporary, size, false));
}
} else {
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
......@@ -911,7 +924,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
if (! left->isVector())
return false;
op = EOpVectorTimesScalarAssign;
setType(TType(type, EvqTemporary, size, false));
setType(TType(type, highestPrecision, EvqTemporary, size, false));
}
} else {
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
......@@ -933,7 +946,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
left->isVector() && right->isMatrix() ||
left->getBasicType() != right->getBasicType())
return false;
setType(TType(type, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
setType(TType(type, highestPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
break;
case EOpEqual:
......@@ -946,7 +959,7 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
left->isVector() && right->isMatrix() ||
left->getBasicType() != right->getBasicType())
return false;
setType(TType(EbtBool));
setType(TType(EbtBool, EbpUndefined));
break;
default:
......@@ -1192,13 +1205,13 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
assert(objectSize == 1);
tempConstArray = new ConstantUnion[1];
tempConstArray->setBConst(*unionArray < *rightUnionArray);
returnType = TType(EbtBool, EvqConst);
returnType = TType(EbtBool, EbpUndefined, EvqConst);
break;
case EOpGreaterThan:
assert(objectSize == 1);
tempConstArray = new ConstantUnion[1];
tempConstArray->setBConst(*unionArray > *rightUnionArray);
returnType = TType(EbtBool, EvqConst);
returnType = TType(EbtBool, EbpUndefined, EvqConst);
break;
case EOpLessThanEqual:
{
......@@ -1207,7 +1220,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
constant.setBConst(*unionArray > *rightUnionArray);
tempConstArray = new ConstantUnion[1];
tempConstArray->setBConst(!constant.getBConst());
returnType = TType(EbtBool, EvqConst);
returnType = TType(EbtBool, EbpUndefined, EvqConst);
break;
}
case EOpGreaterThanEqual:
......@@ -1217,7 +1230,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
constant.setBConst(*unionArray < *rightUnionArray);
tempConstArray = new ConstantUnion[1];
tempConstArray->setBConst(!constant.getBConst());
returnType = TType(EbtBool, EvqConst);
returnType = TType(EbtBool, EbpUndefined, EvqConst);
break;
}
......@@ -1242,7 +1255,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
tempConstArray->setBConst(false);
}
tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst));
tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
tempNode->setLine(getLine());
return tempNode;
......@@ -1268,7 +1281,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
tempConstArray->setBConst(false);
}
tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst));
tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
tempNode->setLine(getLine());
return tempNode;
......@@ -1386,7 +1399,7 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
const TType& t = node->getType();
return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
}
void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
......
......@@ -225,6 +225,24 @@ void TParseContext::binaryOpError(int line, const char* op, TString left, TStrin
op, left.c_str(), right.c_str());
}
bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){
switch( type ){
case EbtFloat:
if( precision == EbpUndefined ){
error( line, "No precision specified for (float)", "", "" );
return true;
}
break;
case EbtInt:
if( precision == EbpUndefined ){
error( line, "No precision specified (int)", "", "" );
return true;
}
break;
}
return false;
}
//
// Both test and if necessary, spit out an error, to see if the node is really
// an l-value that can be operated on this way.
......
......@@ -65,6 +65,7 @@ struct TParseContext {
void assignError(int line, const char* op, TString left, TString right);
void unaryOpError(int line, const char* op, TString operand);
void binaryOpError(int line, const char* op, TString left, TString right);
bool precisionErrorCheck(int line, TPrecision precision, TBasicType type);
bool lValueErrorCheck(int line, const char* op, TIntermTyped*);
bool constErrorCheck(TIntermTyped* node);
bool integerErrorCheck(TIntermTyped* node, const char* token);
......
......@@ -75,7 +75,7 @@ int TType::getStructSize() const
void TVariable::dump(TInfoSink& infoSink) const
{
infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getBasicString();
infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
if (type.isArray()) {
infoSink.debug << "[0]";
}
......@@ -208,4 +208,7 @@ void TSymbolTable::copyTable(const TSymbolTable& copyOf)
for (unsigned int i = 0; i < copyOf.table.size(); ++i) {
table.push_back(copyOf.table[i]->clone(remapper));
}
for( unsigned int i = 0; i < copyOf.precisionStack.size(); i++) {
precisionStack.push_back( copyOf.precisionStack[i] );
}
}
......@@ -129,7 +129,7 @@ class TFunction : public TSymbol {
public:
TFunction(TOperator o) :
TSymbol(0),
returnType(TType(EbtVoid)),
returnType(TType(EbtVoid, EbpUndefined)),
op(o),
defined(false) { }
TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
......@@ -241,6 +241,7 @@ public:
TSymbolTable(TSymbolTable& symTable)
{
table.push_back(symTable.table[0]);
precisionStack.push_back( symTable.precisionStack[0] );
uniqueId = symTable.uniqueId;
}
......@@ -263,12 +264,14 @@ public:
void push()
{
table.push_back(new TSymbolTableLevel);
precisionStack.push_back( PrecisionStackLevel() );
}
void pop()
{
delete table[currentLevel()];
table.pop_back();
precisionStack.pop_back();
}
bool insert(TSymbol& symbol)
......@@ -299,11 +302,37 @@ public:
void dump(TInfoSink &infoSink) const;
void copyTable(const TSymbolTable& copyOf);
void setDefaultPrecision( TBasicType type, TPrecision prec ){
if( type != EbtFloat && type != EbtInt ) return; // Only set default precision for int/float
int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
precisionStack[indexOfLastElement][type] = prec; // Uses map operator [], overwrites the current value
}
// Searches down the precisionStack for a precision qualifier for the specified TBasicType
TPrecision getDefaultPrecision( TBasicType type){
if( type != EbtFloat && type != EbtInt ) return EbpUndefined;
int level = static_cast<int>(precisionStack.size()) - 1;
assert( level >= 0); // Just to be safe. Should not happen.
PrecisionStackLevel::iterator it;
TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
while( level >= 0 ){
it = precisionStack[level].find( type );
if( it != precisionStack[level].end() ){
prec = (*it).second;
break;
}
level--;
}
return prec;
}
protected:
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
bool atDynamicBuiltInLevel() { return table.size() == 2; }
std::vector<TSymbolTableLevel*> table;
typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
std::vector< PrecisionStackLevel > precisionStack;
int uniqueId; // for unique identification in code generation
};
......
......@@ -51,7 +51,7 @@ public:
{
type = bt;
qualifier = q;
precision = EbpHigh;
precision = EbpUndefined;
size = 1;
matrix = false;
array = false;
......@@ -60,11 +60,6 @@ public:
line = ln;
}
void setPrecision(TPrecision pcs)
{
precision = pcs;
}
void setAggregate(int s, bool m = false)
{
size = s;
......@@ -86,7 +81,7 @@ typedef TMap<TTypeList*, TTypeList*>::iterator TStructureMapIterator;
class TType {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
explicit TType(TBasicType t, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false, TPrecision p = EbpHigh) :
explicit TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
{ }
......@@ -99,7 +94,7 @@ public:
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
explicit TType(TTypeList* userDef, const TString& n, TPrecision p = EbpHigh) :
explicit TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
structure(userDef), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) {
typeName = NewPoolTString(n.c_str());
......
......@@ -41,7 +41,7 @@ TString TType::getCompleteString() const
char *p = &buf[0];
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
p += sprintf(p, "%s ", getQualifierString());
p += sprintf(p, "%s %s ", getQualifierString(), getPrecisionString());
if (array)
p += sprintf(p, "array of ");
if (matrix)
......
......@@ -238,6 +238,7 @@ public:
virtual TBasicType getBasicType() const { return type.getBasicType(); }
virtual TQualifier getQualifier() const { return type.getQualifier(); }
virtual TPrecision getPrecision() const { return type.getPrecision(); }
virtual int getNominalSize() const { return type.getNominalSize(); }
virtual int getSize() const { return type.getInstanceSize(); }
virtual bool isMatrix() const { return type.isMatrix(); }
......@@ -334,7 +335,7 @@ public:
bool isConstructor() const;
virtual bool promote(TInfoSink&) { return true; }
protected:
TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat)), op(o) {}
TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
TOperator op;
};
......@@ -416,7 +417,7 @@ protected:
class TIntermSelection : public TIntermTyped {
public:
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
TIntermTyped(TType(EbtVoid)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
virtual void traverse(TIntermTraverser*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment