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:
parent
674014bfc4
commit
5521862729
@ -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_
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -32,4 +32,4 @@
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
bool QualifierWritten(TIntermNode* root, TQualifier);
|
||||
bool QualifierWritten(TIntermNode* root, TStorageQualifier);
|
||||
|
@ -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();
|
||||
//
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -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; }
|
||||
|
@ -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
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user