Implement the full scheme for ES precision qualifiers, generalizing existing storage qualifiers to be able to include multiple independent kinds of qualifiers.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20317 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-01-24 23:10:51 +00:00
parent 674014bfc4
commit 5521862729
15 changed files with 661 additions and 463 deletions

View File

@ -55,7 +55,7 @@ enum TBasicType {
EbtSamplerRectShadow, // ARB_texture_rectangle
EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtStruct,
EbtAddress, // should be deprecated??
EbtNumTypes
};
__inline bool IsSampler(TBasicType type)
@ -69,7 +69,7 @@ __inline bool IsSampler(TBasicType type)
// to allocate variables in. Since built-ins tend to go to different registers
// than varying or uniform, it makes sense they are peers, not sub-classes.
//
enum TQualifier {
enum TStorageQualifier {
EvqTemporary, // For temporaries (within a function), read/write
EvqGlobal, // For globals read/write
EvqConst, // User defined constants and non-output parameters in functions
@ -104,7 +104,7 @@ enum TQualifier {
//
// This is just for debug print out, carried along with the definitions above.
//
__inline const char* getQualifierString(TQualifier q)
__inline const char* getStorageQualifierString(TStorageQualifier q)
{
switch (q) {
case EvqTemporary: return "Temporary"; break;
@ -129,4 +129,22 @@ __inline const char* getQualifierString(TQualifier q)
}
}
enum TPrecisionQualifier {
EpqNone,
EpqLow,
EpqMedium,
EpqHigh
};
__inline const char* getPrecisionQualifierString(TPrecisionQualifier p)
{
switch(p) {
case EpqNone: return ""; break;
case EpqLow: return "lowp"; break;
case EpqMedium: return "mediump"; break;
case EpqHigh: return "highp"; break;
default: return "unknown precision qualifier";
}
}
#endif // _BASICTYPES_INCLUDED_

View File

@ -63,6 +63,13 @@ inline TTypeList* NewPoolTTypeList()
// Not as bad as it looks, there is no actual assumption that the fields
// match up or are name the same or anything like that.
//
class TQualifier {
public:
TStorageQualifier storage : 7;
TPrecisionQualifier precision : 3;
};
class TPublicType {
public:
TBasicType type;
@ -74,10 +81,9 @@ public:
TType* userDef;
int line;
void setBasic(TBasicType bt, TQualifier q, int ln = 0)
void initType(int ln = 0)
{
type = bt;
qualifier = q;
type = EbtVoid;
size = 1;
matrix = false;
array = false;
@ -86,6 +92,18 @@ public:
line = ln;
}
void initQualifiers(bool global = false)
{
qualifier.storage = global ? EvqGlobal : EvqTemporary;
qualifier.precision = EpqNone;
}
void init(int line = 0, bool global = false)
{
initType(line);
initQualifiers(global);
}
void setAggregate(int s, bool m = false)
{
size = s;
@ -107,22 +125,28 @@ typedef std::map<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) :
type(t), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
{ }
explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
type(t), size(s), matrix(m), array(a), arraySize(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
fieldName(0), mangled(0), typeName(0) {
qualifier.storage = q;
qualifier.precision = EpqNone;
}
explicit TType(const TPublicType &p) :
type(p.type), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
type(p.type), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
{
qualifier = p.qualifier;
if (p.userDef) {
structure = p.userDef->getStruct();
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
explicit TType(TTypeList* userDef, const TString& n) :
type(EbtStruct), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
type(EbtStruct), size(1), matrix(false), array(false), arraySize(0),
structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) {
qualifier.storage = EvqTemporary;
qualifier.precision = EpqNone;
typeName = NewPoolTString(n.c_str());
}
explicit TType() {}
@ -206,8 +230,8 @@ public:
}
virtual TBasicType getBasicType() const { return type; }
virtual TQualifier getQualifier() const { return qualifier; }
virtual void changeQualifier(TQualifier q) { qualifier = q; }
virtual TQualifier& getQualifier() { return qualifier; }
virtual const TQualifier& getQualifier() const { return qualifier; }
// One-dimensional size of single instance type
virtual int getNominalSize() const { return size; }
@ -251,7 +275,8 @@ public:
}
}
const char* getBasicString() const { return TType::getBasicString(type); }
const char* getQualifierString() const { return ::getQualifierString(qualifier); }
const char* getStorageQualifierString() const { return ::getStorageQualifierString(qualifier.storage); }
const char* getPrecisionQualifierString() const { return ::getPrecisionQualifierString(qualifier.precision); }
TTypeList* getStruct() { return structure; }
int getObjectSize() const
@ -304,11 +329,12 @@ protected:
void buildMangledName(TString&);
int getStructSize() const;
TBasicType type : 6;
TQualifier qualifier : 7;
TBasicType type : 8;
int size : 8; // size of vector or matrix, not size of array
unsigned int matrix : 1;
unsigned int array : 1;
TQualifier qualifier;
int arraySize;
TTypeList* structure; // 0 unless this is a struct

View File

@ -285,14 +285,14 @@ public:
virtual TType* getTypePointer() { return &type; }
virtual TBasicType getBasicType() const { return type.getBasicType(); }
virtual TQualifier getQualifier() const { return type.getQualifier(); }
virtual TQualifier& getQualifier() { return type.getQualifier(); }
virtual int getNominalSize() const { return type.getNominalSize(); }
virtual int getSize() const { return type.getInstanceSize(); }
virtual bool isMatrix() const { return type.isMatrix(); }
virtual bool isArray() const { return type.isArray(); }
virtual bool isVector() const { return type.isVector(); }
const char* getBasicString() const { return type.getBasicString(); }
const char* getQualifierString() const { return type.getQualifierString(); }
const char* getStorageQualifierString() const { return type.getStorageQualifierString(); }
TString getCompleteString() const { return type.getCompleteString(); }
protected:
@ -451,7 +451,7 @@ public:
virtual void traverse(TIntermTraverser*);
virtual void setUserDefined() { userDefined = true; }
virtual bool isUserDefined() { return userDefined; }
virtual TQualifierList& getQualifier() { return qualifier; }
virtual TQualifierList& getQualifierList() { return qualifier; }
void setOptimize(bool o) { optimize = o; }
void setDebug(bool d) { debug = d; }
bool getOptimize() { return optimize; }

View File

@ -546,13 +546,14 @@ TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nod
TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
{
if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
if (left->getType().getQualifier().storage == EvqConst &&
right->getType().getQualifier().storage == EvqConst) {
return right;
} else {
TIntermTyped *commaAggregate = growAggregate(left, right, line);
commaAggregate->getAsAggregate()->setOperator(EOpComma);
commaAggregate->setType(right->getType());
commaAggregate->getTypePointer()->changeQualifier(EvqTemporary);
commaAggregate->getTypePointer()->getQualifier().storage = EvqTemporary;
return commaAggregate;
}
}
@ -830,7 +831,11 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
// operand. Then only deviations from this need be coded.
//
setType(left->getType());
type.changeQualifier(EvqTemporary);
type.getQualifier().storage = EvqTemporary;
// Fix precision qualifiers
if (right->getQualifier().precision > getQualifier().precision)
getQualifier().precision = right->getQualifier().precision;
//
// Array operations.
@ -1510,7 +1515,8 @@ 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.getQualifier().storage, t.getNominalSize(), t.isMatrix(),
t.isArray()), node->getLine());
}
void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)

View File

@ -44,6 +44,25 @@
//
////////////////////////////////////////////////////////////////////////
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
switchNestingLevel(0), inTypeParen(false),
version(110), profile(ENoProfile), futureCompatibility(false),
contextPragma(true, false)
{
// Default precisions for version 110, to be overridden for
// other versions/profiles/stage combinations
for (int type = 0; type < EbtNumTypes; ++type)
defaultPrecision[type] = EpqHigh;
defaultPrecision[EbtVoid] = EpqNone;
defaultPrecision[EbtDouble] = EpqNone;
defaultPrecision[EbtBool] = EpqNone;
defaultPrecision[EbtVoid] = EpqNone;
}
//
// Look at a '.' field selector string and change it into offsets
// for a vector.
@ -331,7 +350,7 @@ bool TParseContext::lValueErrorCheck(int line, char* op, TIntermTyped* node)
symbol = symNode->getSymbol().c_str();
char* message = 0;
switch (node->getQualifier()) {
switch (node->getQualifier().storage) {
case EvqConst: message = "can't modify a const"; break;
case EvqConstReadOnly: message = "can't modify a const"; break;
case EvqAttribute: message = "can't modify an attribute"; break;
@ -395,7 +414,7 @@ bool TParseContext::lValueErrorCheck(int line, char* op, TIntermTyped* node)
//
bool TParseContext::constErrorCheck(TIntermTyped* node)
{
if (node->getQualifier() == EvqConst)
if (node->getQualifier().storage == EvqConst)
return false;
error(node->getLine(), "constant expression required", "", "");
@ -503,14 +522,14 @@ bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction
overFull = true;
if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
full = true;
if (function[i].type->getQualifier() != EvqConst)
if (function[i].type->getQualifier().storage != EvqConst)
constType = false;
if (function[i].type->isArray())
arrayArg = true;
}
if (constType)
type->changeQualifier(EvqConst);
type->getQualifier().storage = EvqConst;
if (type->isArray() && type->getArraySize() != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor", "");
@ -623,19 +642,19 @@ bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const
bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualifier)
{
switch (qualifier) {
switch (qualifier.storage) {
case EvqIn:
profileRequires(line, ENoProfile, 130, 0, "in for stage inputs");
profileRequires(line, EEsProfile, 300, 0, "in for stage inputs");
qualifier = EvqVaryingIn;
qualifier.storage = EvqVaryingIn;
break;
case EvqOut:
profileRequires(line, ENoProfile, 130, 0, "out for stage outputs");
profileRequires(line, EEsProfile, 300, 0, "out for stage outputs");
qualifier = EvqVaryingOut;
qualifier.storage = EvqVaryingOut;
break;
case EvqInOut:
qualifier = EvqVaryingIn;
qualifier.storage = EvqVaryingIn;
error(line, "cannot use 'inout' at global scope", "", "");
return true;
@ -646,20 +665,34 @@ bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualif
bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
{
if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
if ((pType.qualifier.storage == EvqVaryingIn ||
pType.qualifier.storage == EvqVaryingOut ||
pType.qualifier.storage == EvqAttribute) &&
pType.type == EbtStruct) {
error(line, "cannot be used with a structure", getQualifierString(pType.qualifier), "");
error(line, "cannot be used with a structure", getStorageQualifierString(pType.qualifier.storage), "");
return true;
}
if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
if (pType.qualifier.storage != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
return true;
return false;
}
bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
void TParseContext::setDefaultPrecision(int line, TBasicType type, TPrecisionQualifier qualifier)
{
// TODO: push and pop for nested scopes
if (IsSampler(type) || type == EbtInt || type == EbtFloat) {
defaultPrecision[type] = qualifier;
} else {
error(line, "cannot apply precision statement to this type", TType::getBasicString(type), "");
recover();
}
}
bool TParseContext::parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type)
{
if ((qualifier == EvqOut || qualifier == EvqInOut) &&
type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
@ -741,12 +774,12 @@ bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
//
bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
{
if (type.qualifier == EvqAttribute) {
if (type.qualifier.storage == EvqAttribute) {
error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), "");
return true;
}
if (type.qualifier == EvqConst)
if (type.qualifier.storage == EvqConst)
profileRequires(line, ENoProfile, 120, "GL_3DL_array_objects", "const array");
return false;
@ -899,8 +932,8 @@ bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPubli
//
// Make the qualifier make sense.
//
if (type.qualifier == EvqConst) {
type.qualifier = EvqTemporary;
if (type.qualifier.storage == EvqConst) {
type.qualifier.storage = EvqTemporary;
error(line, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
return true;
}
@ -933,24 +966,24 @@ bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType
return false;
}
bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TType* type)
bool TParseContext::paramErrorCheck(int line, TStorageQualifier qualifier, TType* type)
{
switch (qualifier) {
case EvqConst:
case EvqConstReadOnly:
type->changeQualifier(EvqConstReadOnly);
type->getQualifier().storage = EvqConstReadOnly;
return false;
case EvqIn:
case EvqOut:
case EvqInOut:
type->changeQualifier(qualifier);
type->getQualifier().storage = qualifier;
return false;
case EvqTemporary:
type->changeQualifier(EvqIn);
type->getQualifier().storage = EvqIn;
return false;
default:
type->changeQualifier(EvqIn);
error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), "");
type->getQualifier().storage = EvqIn;
error(line, "qualifier not allowed on function parameter", getStorageQualifierString(qualifier), "");
return true;
}
}
@ -1016,9 +1049,9 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
//
// identifier must be of type constant, a global, or a temporary
//
TQualifier qualifier = variable->getType().getQualifier();
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), "");
error(line, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
return true;
}
//
@ -1026,15 +1059,15 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
//
if (qualifier == EvqConst) {
if (qualifier != initializer->getType().getQualifier()) {
if (qualifier != initializer->getType().getQualifier().storage) {
error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
if (type != initializer->getType()) {
error(line, " non-matching types for const initializer ",
variable->getType().getQualifierString(), "");
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getStorageQualifierString(), "");
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
if (initializer->getAsConstantUnion()) {
@ -1053,7 +1086,7 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
variable->shareConstPointer(constArray);
} else {
error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
}

View File

@ -67,12 +67,7 @@ struct TPragma {
// they can be passed to the parser without needing a global.
//
struct TParseContext {
TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
switchNestingLevel(0), inTypeParen(false),
version(110), profile(ENoProfile), futureCompatibility(false),
contextPragma(true, false) { }
TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is);
TIntermediate& intermediate; // to hold and build a parse tree
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
TInfoSink& infoSink;
@ -93,6 +88,7 @@ struct TParseContext {
TMap<TString, TBehavior> extensionBehavior; // for each extension string, what it's current enablement is
struct TPragma contextPragma;
TPrecisionQualifier defaultPrecision[EbtNumTypes];
TString HashErrMsg;
bool AfterEOF;
@ -125,11 +121,12 @@ struct TParseContext {
bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
bool globalQualifierFixAndErrorCheck(int line, TQualifier&);
bool structQualifierErrorCheck(int line, const TPublicType& pType);
bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
void setDefaultPrecision(int line, TBasicType, TPrecisionQualifier);
bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type);
bool containsSampler(TType& type);
bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
bool paramErrorCheck(int line, TQualifier qualifier, TType* type);
bool paramErrorCheck(int line, TStorageQualifier qualifier, TType* type);
const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);

View File

@ -36,7 +36,7 @@
class TAliveTraverser : public TIntermTraverser {
public:
TAliveTraverser(TQualifier q) : TIntermTraverser(), found(false), qualifier(q)
TAliveTraverser(TStorageQualifier q) : TIntermTraverser(), found(false), qualifier(q)
{
visitSymbol = AliveSymbol;
visitSelection = AliveSelection;
@ -45,7 +45,7 @@ public:
bool wasFound() { return found; }
protected:
bool found;
TQualifier qualifier;
TStorageQualifier qualifier;
friend void AliveSymbol(TIntermSymbol*, TIntermTraverser*);
friend bool AliveSelection(bool, TIntermSelection*, TIntermTraverser*);
@ -59,7 +59,7 @@ protected:
// ?? It does not do this well yet, this is just a place holder
// that simply determines if it was reference at all, anywhere.
//
bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
{
TAliveTraverser it(qualifier);
@ -76,7 +76,7 @@ void AliveSymbol(TIntermSymbol* node, TIntermTraverser* it)
//
// If it's what we're looking for, record it.
//
if (node->getQualifier() == lit->qualifier)
if (node->getQualifier().storage == lit->qualifier)
lit->found = true;
}

View File

@ -32,4 +32,4 @@
//POSSIBILITY OF SUCH DAMAGE.
//
bool QualifierWritten(TIntermNode* root, TQualifier);
bool QualifierWritten(TIntermNode* root, TStorageQualifier);

View File

@ -92,12 +92,11 @@ int ShInitialize()
SetGlobalPoolAllocatorPtr(gPoolAllocator);
symTables[EShLangVertex].pop();
symTables[EShLangFragment].pop();
symTables[EShLangVertex].pop(0);
symTables[EShLangFragment].pop(0);
builtInPoolAllocator->popAll();
delete builtInPoolAllocator;
}
return ret ? 1 : 0;
@ -343,7 +342,7 @@ int ShCompile(
// throwing away all but the built-ins.
//
while (! symbolTable.atSharedBuiltInLevel())
symbolTable.pop();
symbolTable.pop(0);
FinalizePreprocessor();
//

View File

@ -111,7 +111,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.getStorageQualifierString() << " " << type.getBasicString();
if (type.isArray()) {
infoSink.debug << "[0]";
}
@ -154,6 +154,8 @@ TSymbolTableLevel::~TSymbolTableLevel()
{
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
delete (*it).second;
delete [] defaultPrecision;
}
//

View File

@ -103,7 +103,7 @@ public:
TType& getType() { return type; }
const TType& getType() const { return type; }
bool isUserType() const { return userType; }
void changeQualifier(TQualifier qualifier) { type.changeQualifier(qualifier); }
void setStorageQualifier(TStorageQualifier qualifier) { type.getQualifier().storage = qualifier; }
void updateArrayInformationType(TType *t) { arrayInformationType = t; }
TType* getArrayInformationType() { return arrayInformationType; }
@ -201,7 +201,7 @@ protected:
class TSymbolTableLevel {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
TSymbolTableLevel() { }
TSymbolTableLevel() : defaultPrecision (0) { }
~TSymbolTableLevel();
bool insert(TSymbol& symbol)
@ -224,6 +224,32 @@ public:
return (*it).second;
}
// Use this to do a lazy 'push' of precision defaults the first time
// a precision statement is seen in a new scope. Leave it at 0 for
// when no push was needed. Thus, it is not the current defaults,
// it is what to restore the defaults to when popping a level.
void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
{
// can call multiple times at one scope, will only latch on first call,
// as we're tracking the previous scope's values, not the current values
if (defaultPrecision != 0)
return;
defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
for (int t = 0; t < EbtNumTypes; ++t)
defaultPrecision[t] = p[t];
}
void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
{
// can be called for table level pops that didn't set the
// defaults
if (defaultPrecision == 0 || p == 0)
return;
for (int t = 0; t < EbtNumTypes; ++t)
p[t] = defaultPrecision[t];
}
void relateToOperator(const char* name, TOperator op);
void dump(TInfoSink &infoSink) const;
@ -235,6 +261,7 @@ protected:
typedef std::pair<tLevel::iterator, bool> tInsertResult;
tLevel level;
TPrecisionQualifier *defaultPrecision;
};
class TSymbolTable {
@ -258,7 +285,7 @@ public:
{
// level 0 is always built In symbols, so we never pop that out
while (table.size() > 1)
pop();
pop(0);
}
//
@ -270,11 +297,15 @@ public:
bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
bool atSharedBuiltInLevel() { return table.size() == 1; }
bool atGlobalLevel() { return table.size() <= 3; }
void push() {
void push()
{
table.push_back(new TSymbolTableLevel);
}
void pop() {
void pop(TPrecisionQualifier *p)
{
table[currentLevel()]->getPreviousDefaultPrecisions(p);
delete table[currentLevel()];
table.pop_back();
}
@ -307,6 +338,8 @@ public:
void dump(TInfoSink &infoSink) const;
void copyTable(const TSymbolTable& copyOf);
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
protected:
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
bool atDynamicBuiltInLevel() { return table.size() == 2; }

View File

@ -732,6 +732,24 @@ void SetVersion(int version)
{
TParseContext& parseContext = *((TParseContext *)cpp->pC);
parseContext.version = version;
if (version == 100 || version == 300) {
for (int type = 0; type < EbtNumTypes; ++type)
parseContext.defaultPrecision[type] = EpqNone;
if (parseContext.language == EShLangVertex) {
parseContext.defaultPrecision[EbtInt] = EpqHigh;
parseContext.defaultPrecision[EbtFloat] = EpqHigh;
parseContext.defaultPrecision[EbtSampler2D] = EpqLow;
parseContext.defaultPrecision[EbtSamplerCube] = EpqLow;
}
if (parseContext.language == EShLangFragment) {
parseContext.defaultPrecision[EbtInt] = EpqMedium;
parseContext.defaultPrecision[EbtSampler2D] = EpqLow;
parseContext.defaultPrecision[EbtSamplerCube] = EpqLow;
}
}
}
const int FirstProfileVersion = 150;

File diff suppressed because it is too large Load Diff

View File

@ -60,10 +60,12 @@ TString TType::getCompleteString() const
char *p = &buf[0];
char *end = &buf[maxSize];
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
p += sprintf_s(p, end - p, "%s ", getQualifierString());
if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal)
p += sprintf_s(p, end - p, "%s ", getStorageQualifierString());
if (array)
p += sprintf_s(p, end - p, "array of ");
if (qualifier.precision != EpqNone)
p += sprintf_s(p, end - p, "%s ", getPrecisionQualifierString());
if (matrix)
p += sprintf_s(p, end - p, "%dX%d matrix of ", size, size);
else if (size > 1)

View File

@ -69,15 +69,15 @@ void ParseSymbol(TIntermSymbol* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
return;
return;
}
bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
TQualifier qualifier = node->getType().getQualifier();
TStorageQualifier qualifier = node->getType().getQualifier().storage;
if (qualifier != EvqConst) {
const int maxSize = 200;
@ -85,6 +85,7 @@ bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to %s", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
@ -102,6 +103,7 @@ bool ParseUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
@ -115,11 +117,13 @@ bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverse
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
if (node->getSequence().size() == 0) {
oit->error = true;
return false;
}
@ -152,6 +156,7 @@ bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverse
oit->isMatrix = false;
oit->matrixSize = 0;
}
return false;
}
@ -229,6 +234,7 @@ bool ParseLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it)
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
oit->error = true;
return false;
}
@ -237,6 +243,7 @@ bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
oit->error = true;
return false;
}