diff --git a/Test/120.frag b/Test/120.frag index 6c35332c..1e25af8b 100644 --- a/Test/120.frag +++ b/Test/120.frag @@ -9,6 +9,9 @@ float precision; in vec4 i; out vec4 o; +uniform sampler2D s2D; +centroid varying vec2 centTexCoord; + uniform mat4x2 m; struct s { @@ -58,4 +61,6 @@ void main() b = a; // ERROR b = b + f; // ERROR f |= b; // ERROR + + gl_FragColor = texture2D(s2D, centTexCoord); } diff --git a/Test/120.vert b/Test/120.vert new file mode 100644 index 00000000..c729ca4e --- /dev/null +++ b/Test/120.vert @@ -0,0 +1,18 @@ +#version 120 + +in vec4 i; +out vec4 o; + +attribute vec2 attv2; +attribute vec4 attv4; +uniform sampler2D s2D; +invariant varying vec2 centTexCoord; +invariant gl_Position; + +centroid centroid foo; + +void main() +{ + centTexCoord = attv2; + gl_Position = attv4; +} diff --git a/Test/testlist b/Test/testlist index 0921ddd6..672b281f 100644 --- a/Test/testlist +++ b/Test/testlist @@ -6,6 +6,7 @@ versionsClean.frag versionsClean.vert versionsErrors.frag versionsErrors.vert +120.vert 120.frag 130.frag 140.frag diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 0f19eca3..22c88cb3 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -169,19 +169,52 @@ inline TArraySizes NewPoolTArraySizes() } // -// This is a workaround for a problem with the yacc stack, It can't have +// TPublicType is a workaround for a problem with the yacc stack, It can't have // types that it thinks have non-trivial constructors. It should // just be used while recognizing the grammar, not anything else. Pointers // could be used, but also trying to avoid lots of memory management overhead. // // 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. +// match up or are named the same or anything like that. // class TQualifier { public: + void clear() + { + storage = EvqTemporary; + precision = EpqNone; + buffer = false; + invariant = false; + centroid = false; + smooth = false; + flat = false; + nopersp = false; + patch = false; + sample = false; + shared = false; + coherent = false; + volatil = false; + restrict = false; + readonly = false; + writeonly = false; + } TStorageQualifier storage : 7; TPrecisionQualifier precision : 3; + bool buffer : 1; + bool invariant : 1; + bool centroid : 1; + bool smooth : 1; + bool flat : 1; + bool nopersp : 1; + bool patch : 1; + bool sample : 1; + bool shared : 1; + bool coherent : 1; + bool volatil : 1; + bool restrict : 1; + bool readonly : 1; + bool writeonly : 1; }; class TPublicType { @@ -209,8 +242,9 @@ public: void initQualifiers(bool global = false) { - qualifier.storage = global ? EvqGlobal : EvqTemporary; - qualifier.precision = EpqNone; + qualifier.clear(); + if (global) + qualifier.storage = EvqGlobal; } void init(int line = 0, bool global = false) @@ -249,8 +283,8 @@ public: fieldName(0), mangled(0), typeName(0) { sampler.clear(); + qualifier.clear(); qualifier.storage = q; - qualifier.precision = EpqNone; } TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) : type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0), @@ -258,6 +292,7 @@ public: fieldName(0), mangled(0), typeName(0) { sampler.clear(); + qualifier.clear(); qualifier.storage = q; qualifier.precision = p; assert(p >= 0 && p <= EpqHigh); @@ -278,8 +313,7 @@ public: structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) { sampler.clear(); - qualifier.storage = EvqTemporary; - qualifier.precision = EpqNone; + qualifier.clear(); typeName = NewPoolTString(n.c_str()); } explicit TType() {} @@ -421,11 +455,39 @@ public: TString TType::getCompleteString() const { - const int maxSize = 100; + const int maxSize = 200; char buf[maxSize]; char *p = &buf[0]; char *end = &buf[maxSize]; + if (qualifier.buffer) + p += snprintf(p, end - p, "buffer "); + if (qualifier.invariant) + p += snprintf(p, end - p, "invariant "); + if (qualifier.centroid) + p += snprintf(p, end - p, "centroid "); + if (qualifier.smooth) + p += snprintf(p, end - p, "smooth "); + if (qualifier.flat) + p += snprintf(p, end - p, "flat "); + if (qualifier.nopersp) + p += snprintf(p, end - p, "noperspective "); + if (qualifier.patch) + p += snprintf(p, end - p, "patch "); + if (qualifier.sample) + p += snprintf(p, end - p, "sample "); + if (qualifier.shared) + p += snprintf(p, end - p, "shared "); + if (qualifier.coherent) + p += snprintf(p, end - p, "coherent "); + if (qualifier.volatil) + p += snprintf(p, end - p, "volatile "); + if (qualifier.restrict) + p += snprintf(p, end - p, "restrict "); + if (qualifier.readonly) + p += snprintf(p, end - p, "readonly "); + if (qualifier.writeonly) + p += snprintf(p, end - p, "writeonly "); if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal) p += snprintf(p, end - p, "%s ", getStorageQualifierString()); if (arraySizes) { diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 419021d0..f404b145 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -668,6 +668,62 @@ bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType return false; } +// +// Merge characteristics of the 'right' qualifier into the 'left'. +// If there is duplication, issue error messages. +// +// Return true if there was an error. +// +bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right) +{ + bool bad = false; + + // Storage qualification + if (left.qualifier.storage == EvqTemporary) + left.qualifier.storage = right.qualifier.storage; + else if (left.qualifier.storage == EvqIn && right.qualifier.storage == EvqOut || + left.qualifier.storage == EvqOut && right.qualifier.storage == EvqIn) + left.qualifier.storage = EvqInOut; + else if (left.qualifier.storage == EvqIn && right.qualifier.storage == EvqConst || + left.qualifier.storage == EvqConst && right.qualifier.storage == EvqIn) + left.qualifier.storage = EvqConstReadOnly; + else if ( left.qualifier.storage != EvqTemporary && + right.qualifier.storage != EvqTemporary) { + error(line, "too many storage qualifiers", getStorageQualifierString(right.qualifier.storage), ""); + bad = true; + } + + // Precision qualifiers + if (left.qualifier.precision == EpqNone) + left.qualifier.precision = right.qualifier.precision; + else if (right.qualifier.precision) { + error(line, "only one precision qualifier allowed", getPrecisionQualifierString(right.qualifier.precision), ""); + bad = true; + } + + // other qualifiers + #define MERGE_SINGLETON(field) bad |= left.qualifier.field && right.qualifier.field; left.qualifier.field |= right.qualifier.field; + MERGE_SINGLETON(buffer); + MERGE_SINGLETON(invariant); + MERGE_SINGLETON(centroid); + MERGE_SINGLETON(smooth); + MERGE_SINGLETON(flat); + MERGE_SINGLETON(nopersp); + MERGE_SINGLETON(patch); + MERGE_SINGLETON(sample); + MERGE_SINGLETON(shared); + MERGE_SINGLETON(coherent); + MERGE_SINGLETON(volatil); + MERGE_SINGLETON(restrict); + MERGE_SINGLETON(readonly); + MERGE_SINGLETON(writeonly); + + if (bad) + error(line, "replicated qualifiers", "", ""); + + return bad; +} + void TParseContext::setDefaultPrecision(int line, TBasicType type, TPrecisionQualifier qualifier) { if (type == EbtSampler || type == EbtInt || type == EbtFloat) { diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index c57ce327..4044d1e6 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -120,6 +120,7 @@ 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 mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right); void setDefaultPrecision(int line, TBasicType, TPrecisionQualifier); bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type); bool containsSampler(const TType& type); diff --git a/glslang/MachineIndependent/glslang.l b/glslang/MachineIndependent/glslang.l index 1b3f34cb..c80545f3 100644 --- a/glslang/MachineIndependent/glslang.l +++ b/glslang/MachineIndependent/glslang.l @@ -268,30 +268,30 @@ int yy_input(char* buf, int max_size); "image3D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE3D); } "iimage3D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE3D); } "uimage3D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE3D); } -"image2Drect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DRECT); } -"iimage2Drect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DRECT); } -"uimage2Drect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DRECT); } +"image2DRect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DRECT); } +"iimage2DRect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DRECT); } +"uimage2DRect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DRECT); } "imageCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGECUBE); } "iimageCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGECUBE); } "uimageCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGECUBE); } "imageBuffer" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGEBUFFER); } "iimageBuffer" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGEBUFFER); } "uimageBuffer" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGEBUFFER); } -"image1Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE1DARRAY); } -"iimage1Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE1DARRAY); } -"uimage1Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE1DARRAY); } -"image2Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DARRAY); } -"iimage2Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DARRAY); } -"uimage2Darray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DARRAY); } -"imageCubearray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGECUBEARRAY); } -"iimageCubearray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGECUBEARRAY); } -"uimageCubearray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGECUBEARRAY); } +"image1DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE1DARRAY); } +"iimage1DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE1DARRAY); } +"uimage1DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE1DARRAY); } +"image2DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DARRAY); } +"iimage2DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DARRAY); } +"uimage2DArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DARRAY); } +"imageCubeArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGECUBEARRAY); } +"iimageCubeArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGECUBEARRAY); } +"uimageCubeArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGECUBEARRAY); } "image2DMS" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DMS); } "iimage2DMS" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DMS); } "uimage2DMS" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DMS); } -"image2DMSarray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DMSARRAY); } -"iimage2DMSarray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DMSARRAY); } -"uimage2DMSarray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DMSARRAY); } +"image2DMSArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IMAGE2DMSARRAY); } +"iimage2DMSArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(IIMAGE2DMSARRAY); } +"uimage2DMSArray" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(UIMAGE2DMSARRAY); } "struct" { pyylval->lex.line = yylineno; return(STRUCT); } diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 9ae857c8..711e26a6 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -1601,20 +1601,42 @@ fully_specified_type invariant_qualifier : INVARIANT { + parseContext.profileRequires($$.line, ENoProfile, 120, 0, "invariant"); + $$.init($1.line); + $$.qualifier.invariant = true; } ; interpolation_qualifier : SMOOTH { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "smooth")) + parseContext.recover(); + parseContext.profileRequires($$.line, ENoProfile, 130, 0, "smooth"); + parseContext.profileRequires($$.line, EEsProfile, 300, 0, "smooth"); + $$.init($1.line); + $$.qualifier.smooth = true; } | FLAT { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "flat")) + parseContext.recover(); + parseContext.profileRequires($$.line, ENoProfile, 130, 0, "flat"); + parseContext.profileRequires($$.line, EEsProfile, 300, 0, "flat"); + $$.init($1.line); + $$.qualifier.flat = true; } | NOPERSPECTIVE { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "noperspective")) + parseContext.recover(); + parseContext.requireProfile($$.line, static_cast(~EEsProfileMask), "noperspective"); + parseContext.profileRequires($$.line, ENoProfile, 130, 0, "noperspective"); + $$.init($1.line); + $$.qualifier.nopersp = true; } ; layout_qualifier : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { + $$.init($1.line); } ; @@ -1635,6 +1657,7 @@ layout_qualifier_id precise_qualifier : PRECISE { + $$.init($1.line); } ; @@ -1644,24 +1667,11 @@ type_qualifier } | type_qualifier single_type_qualifier { $$ = $1; - // TODO: merge qualifiers in $1 and $2 and check for duplication - - if ($$.type == EbtVoid) { + if ($$.type == EbtVoid) $$.type = $2.type; - } - if ($$.qualifier.storage == EvqTemporary) { - $$.qualifier.storage = $2.qualifier.storage; - } else if ($$.qualifier.storage == EvqIn && $2.qualifier.storage == EvqOut || - $$.qualifier.storage == EvqOut && $2.qualifier.storage == EvqIn) { - $$.qualifier.storage = EvqInOut; - } else if ($$.qualifier.storage == EvqIn && $2.qualifier.storage == EvqConst || - $$.qualifier.storage == EvqConst && $2.qualifier.storage == EvqIn) { - $$.qualifier.storage = EvqConstReadOnly; - } - - if ($$.qualifier.precision == EpqNone) - $$.qualifier.precision = $2.qualifier.precision; + if (parseContext.mergeQualifiersErrorCheck($$.line, $$, $2)) + parseContext.recover(); } ; @@ -1741,24 +1751,24 @@ storage_qualifier $$.qualifier.storage = EvqOut; } | CENTROID { + parseContext.profileRequires($$.line, ENoProfile, 120, 0, "centroid"); + parseContext.profileRequires($$.line, EEsProfile, 300, 0, "centroid"); if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "centroid")) parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqVaryingIn; + $$.qualifier.centroid = true; } | PATCH { - // TODO: implement this qualifier if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "patch")) parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.patch = true; } | SAMPLE { - // TODO: implement this qualifier if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "sample")) parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.sample = true; } | UNIFORM { if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform")) @@ -1770,48 +1780,32 @@ storage_qualifier if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "buffer")) parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.storage = EvqUniform; + $$.qualifier.buffer = true; } | SHARED { - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "shared")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.shared = true; } | COHERENT { - // TODO: implement this qualifier - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "coherent")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.coherent = true; } | VOLATILE { - // TODO: implement this qualifier - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "volatile")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.volatil = true; } | RESTRICT { - // TODO: implement this qualifier - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "restrict")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.restrict = true; } | READONLY { - // TODO: implement this qualifier - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "readonly")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.readonly = true; } | WRITEONLY { - // TODO: implement this qualifier - if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "writeonly")) - parseContext.recover(); $$.init($1.line); - $$.qualifier.storage = EvqUniform; + $$.qualifier.writeonly = true; } | SUBROUTINE { if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "subroutine"))