diff --git a/Test/120.vert b/Test/120.vert index 9e8afbc3..d0f64e40 100644 --- a/Test/120.vert +++ b/Test/120.vert @@ -8,8 +8,9 @@ attribute vec4 attv4; uniform sampler2D s2D; invariant varying vec2 centTexCoord; invariant gl_Position; - +centroid gl_Position; centroid centroid foo; +invariant gl_Position, gl_PointSize; void main() { @@ -22,6 +23,8 @@ void main() float f[]; int a = f.length(); + + gl_PointSize = 3.8; } uniform float initted = 3.4; diff --git a/Test/specExamples.vert b/Test/specExamples.vert index c4b283c2..bf148fa0 100644 --- a/Test/specExamples.vert +++ b/Test/specExamples.vert @@ -97,8 +97,8 @@ layout (binding=3) uniform atomic_uint c2; // offset = 8 layout (binding=2) uniform atomic_uint d2; // offset = 4 //layout (offset=4) // error, must include binding -layout (binding=1, offset=0) a; // okay -layout (binding=2, offset=0) b; // okay +//layout (binding=1, offset=0) a; // okay +//layout (binding=2, offset=0) b; // okay //layout (binding=1, offset=0) c; // error, offsets must not be shared // // between a and c //layout (binding=1, offset=2) d; // error, overlaps offset 0 of a diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 02f991b0..5fd3a7d0 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -154,6 +154,14 @@ inline TTypeList* NewPoolTTypeList() return new(memory) TTypeList; } +typedef TVector TIdentifierList; + +inline TIdentifierList* NewPoolTIdentifierList() +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TIdentifierList)); + return new(memory) TIdentifierList; +} + // // TODO: memory: TArraySizes can be replaced by something smaller. // Almost all arrays could be handled by two sizes each fitting @@ -236,7 +244,7 @@ public: bool isMemory() const { - return coherent || volatil || restrict || readonly || writeonly; + return shared || coherent || volatil || restrict || readonly || writeonly; } bool isInterpolation() const { diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 9e396340..a32ea21a 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -48,12 +48,15 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E version(v), profile(p), forwardCompatible(fc), messages(m), contextPragma(true, false) { + // set all precision defaults to EpqNone, which is correct for all desktop types + // and for ES types that don't have defaults (thus getting an error on use) for (int type = 0; type < EbtNumTypes; ++type) defaultPrecision[type] = EpqNone; for (int type = 0; type < maxSamplerIndex; ++type) defaultSamplerPrecision[type] = EpqNone; + // replace with real defaults for those that have them if (profile == EEsProfile) { TSampler sampler; sampler.set(EbtFloat, Esd2D); @@ -67,13 +70,11 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E defaultPrecision[EbtUint] = EpqHigh; defaultPrecision[EbtFloat] = EpqHigh; defaultPrecision[EbtSampler] = EpqLow; - // TODO: functionality: need default precisions per sampler type break; case EShLangFragment: defaultPrecision[EbtInt] = EpqMedium; defaultPrecision[EbtUint] = EpqMedium; defaultPrecision[EbtSampler] = EpqLow; - // TODO: semantics: give error when using float in frag shader without default precision break; default: error(1, "INTERNAL ERROR", "unexpected language", ""); @@ -1607,6 +1608,36 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta } } +// For an identifier that is already declared, add more qualification to it. +void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, const TString& identifier) +{ + TSymbol* existing = symbolTable.find(identifier); + TVariable* variable = existing ? existing->getAsVariable() : 0; + if (! variable) { + error(line, "identifier not previously declared", identifier.c_str(), ""); + + return; + } + + if (qualifier.isAuxillary() || + qualifier.isMemory() || + qualifier.isInterpolation() || + qualifier.storage != EvqTemporary || + qualifier.precision != EpqNone) { + error(line, "cannot add this qualifier to an existing variable", identifier.c_str(), ""); + + return; + } + + variable->getType().getQualifier().invariant = true; +} + +void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, TIdentifierList& identifiers) +{ + for (unsigned int i = 0; i < identifiers.size(); ++i) + addQualifierToExisting(line, qualifier, *identifiers[i]); +} + // // Take the sequence of statements that has been built up since the last case/default, // put it on the list of top-level nodes for the current (inner-most) switch statement, diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index d5a215a2..04a80b59 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -154,6 +154,8 @@ struct TParseContext { TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset); void addBlock(int line, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0); + void addQualifierToExisting(int line, TQualifier, const TString& identifier); + void addQualifierToExisting(int line, TQualifier, TIdentifierList&); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body); void updateDefaults(int line, const TPublicType&, const TString* id); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index a7995f94..42e0635b 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -103,6 +103,7 @@ extern void yyerror(const char*); TTypeLine typeLine; TTypeList* typeList; TArraySizes arraySizes; + TIdentifierList* identifierList; }; } interm; } @@ -214,6 +215,8 @@ extern void yyerror(const char*); %type function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype %type function_call_or_method function_identifier function_call_header +%type identifier_list + %start translation_unit %% @@ -1120,15 +1123,12 @@ declaration $$ = 0; } | type_qualifier IDENTIFIER SEMICOLON { - // TODO: functionality: track what variables are declared with INVARIANT - // precise foo; - // invariant foo; + parseContext.addQualifierToExisting($1.line, $1.qualifier, *$2.string); $$ = 0; } | type_qualifier IDENTIFIER identifier_list SEMICOLON { - // TODO: functionality: track what variables are declared with INVARIANT - // precise foo, bar; - // invariant foo, bar; + $3->push_back($2.string); + parseContext.addQualifierToExisting($1.line, $1.qualifier, *$3); $$ = 0; } ; @@ -1144,8 +1144,12 @@ block_structure identifier_list : COMMA IDENTIFIER { + $$ = NewPoolTIdentifierList(); + $$->push_back($2.string); } | identifier_list COMMA IDENTIFIER { + $$ = $1; + $$->push_back($3.string); } ;