diff --git a/Test/300layout.vert b/Test/300layout.vert index fd177ddb..89fb17b6 100644 --- a/Test/300layout.vert +++ b/Test/300layout.vert @@ -1,30 +1,30 @@ #version 300 es -layout(location = 7) in vec4 c; +layout(location = 7) in vec3 c; layout(LocatioN = 3) in vec4 p; out vec4 pos; -out vec4 color; +out vec3 color; layout(shared, column_major, row_major) uniform mat4 m4; // default is now shared and row_major -//layout(std140) uniform Transform { // layout of this block is std140 -// mat4 M1; // row_major -// layout(column_major) mat4 M2; // column major -// mat3 N1; // row_major -//}; -// +layout(std140) uniform Transform { // layout of this block is std140 + mat4 M1; // row_major + layout(column_major) mat4 M2; // column major + mat3 N1; // row_major +} tblock; + //uniform T2 { // layout of this block is shared //... //}; // -//layout(column_major) uniform T3 { // shared and column_major -// mat4 M3; // column_major -// layout(row_major) mat4 m4; // row major -// mat3 N2; // column_major -//}; +layout(column_major) uniform T3 { // shared and column_major + mat4 M3; // column_major + layout(row_major) mat4 m4; // row major + mat3 N2; // column_major +}; void main() { - pos = p * m4; - color = c; + pos = p * (m4 + tblock.M1 + tblock.M2); + color = c * tblock.N1; } diff --git a/Test/specExamples.vert b/Test/specExamples.vert index ab51872d..bc406a9b 100644 --- a/Test/specExamples.vert +++ b/Test/specExamples.vert @@ -61,7 +61,7 @@ layout(row_major, column_major) layout(shared, row_major) uniform; // default is now shared and row_major -layout(std140) uniform Transform { // layout of this block is std140 +layout(std140) uniform Transform2 { // layout of this block is std140 mat4 M1; // row_major layout(column_major) mat4 M2; // column major mat3 N1; // row_major @@ -124,7 +124,7 @@ coherent buffer Block { vec4 member2; }; -buffer Block { +buffer Block2 { coherent readonly vec4 member1; coherent vec4 member2; }; diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h index 367ce36e..b3f592a0 100644 --- a/glslang/Include/BaseTypes.h +++ b/glslang/Include/BaseTypes.h @@ -49,6 +49,7 @@ enum TBasicType { EbtBool, EbtSampler, EbtStruct, + EbtBlock, EbtNumTypes }; diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index b13f3314..2785e504 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -351,7 +351,7 @@ typedef std::map::const_iterator TStructureMapIterator; class TType { public: POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) - explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) : + TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) : type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0), structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) @@ -360,7 +360,7 @@ public: qualifier.clear(); qualifier.storage = q; } - TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) : + 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), structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) @@ -382,15 +382,20 @@ public: typeName = NewPoolTString(p.userDef->getTypeName().c_str()); } } - explicit TType(TTypeList* userDef, const TString& n) : + TType(TTypeList* userDef, const TString& n, TStorageQualifier blockQualifier = EvqGlobal) : type(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0), structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) { sampler.clear(); qualifier.clear(); + // is it an interface block? + if (blockQualifier != EvqGlobal) { + qualifier.storage = blockQualifier; + type = EbtBlock; + } typeName = NewPoolTString(n.c_str()); } - explicit TType() {} + TType() {} virtual ~TType() {} TType(const TType& type) { *this = type; } @@ -513,6 +518,9 @@ public: void setArrayInformationType(TType* t) { arrayInformationType = t; } TType* getArrayInformationType() { return arrayInformationType; } virtual bool isVector() const { return vectorSize > 1; } + const char* getBasicString() const { + return TType::getBasicString(type); + } static const char* getBasicString(TBasicType t) { switch (t) { case EbtVoid: return "void"; @@ -523,6 +531,7 @@ public: case EbtBool: return "bool"; case EbtSampler: return "sampler/image"; case EbtStruct: return "structure"; + case EbtBlock: return "block"; default: return "unknown type"; } } @@ -598,10 +607,9 @@ public: if (type == EbtSampler) return sampler.getString(); else - return getBasicString(type); + return getBasicString(); } - const char* getBasicString() const { return TType::getBasicString(type); } const char* getStorageQualifierString() const { return ::getStorageQualifierString(qualifier.storage); } const char* getPrecisionQualifierString() const { return ::getPrecisionQualifierString(qualifier.precision); } TTypeList* getStruct() { return structure; } @@ -610,7 +618,7 @@ public: { int totalSize; - if (getBasicType() == EbtStruct) + if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) totalSize = getStructSize(); else if (matrixCols) totalSize = matrixCols * matrixRows; diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 117fe3c3..5e6bb03f 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -71,6 +71,9 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType // TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line) { + if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock) + return 0; + switch (op) { case EOpLessThan: case EOpGreaterThan: @@ -199,6 +202,9 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, { TIntermTyped* child = childNode->getAsTyped(); + if (child->getType().getBasicType() == EbtBlock) + return 0; + if (child == 0) { infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); return 0; diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 363af601..7c0de795 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -717,43 +717,43 @@ bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualif } // -// Merge characteristics of the 'right' qualifier into the 'left'. -// If there is duplication, issue error messages. +// Merge characteristics of the 'src' qualifier into the 'dst'. +// If there is duplication, issue error messages, unless 'force' +// is specified, which means to just override default settings. // // Return true if there was an error. // -bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right) +bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& dst, const TPublicType& src, bool force) { 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), ""); + if (dst.qualifier.storage == EvqTemporary || dst.qualifier.storage == EvqGlobal) + dst.qualifier.storage = src.qualifier.storage; + else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqOut || + dst.qualifier.storage == EvqOut && src.qualifier.storage == EvqIn) + dst.qualifier.storage = EvqInOut; + else if (dst.qualifier.storage == EvqIn && src.qualifier.storage == EvqConst || + dst.qualifier.storage == EvqConst && src.qualifier.storage == EvqIn) + dst.qualifier.storage = EvqConstReadOnly; + else if (src.qualifier.storage != EvqTemporary) { + error(line, "too many storage qualifiers", getStorageQualifierString(src.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), ""); + if (! force && src.qualifier.precision != EpqNone && dst.qualifier.precision != EpqNone) { + error(line, "only one precision qualifier allowed", getPrecisionQualifierString(src.qualifier.precision), ""); bad = true; } + if (dst.qualifier.precision == EpqNone || force && src.qualifier.precision != EpqNone) + dst.qualifier.precision = src.qualifier.precision; // Layout qualifiers - mergeLayoutQualifiers(line, left, right); + mergeLayoutQualifiers(line, dst, src); // other qualifiers - #define MERGE_SINGLETON(field) bad |= left.qualifier.field && right.qualifier.field; left.qualifier.field |= right.qualifier.field; + #define MERGE_SINGLETON(field) bad |= dst.qualifier.field && src.qualifier.field; dst.qualifier.field |= src.qualifier.field; MERGE_SINGLETON(invariant); MERGE_SINGLETON(centroid); MERGE_SINGLETON(smooth); @@ -1461,6 +1461,72 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ return converted; } +// +// Do everything needed to add an interface block. +// +void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes) +{ + // First, error checks + + if (reservedErrorCheck(line, blockName)) { + recover(); + + return; + } + if (instanceName && reservedErrorCheck(line, *instanceName)) { + recover(); + + return; + } + if (qualifier.type != EbtVoid) { + error(line, "interface blocks cannot be declared with a type", blockName.c_str(), ""); + recover(); + + return; + } + if (qualifier.qualifier.storage == EvqUniform) { + requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block"); + profileRequires(line, EEsProfile, 300, 0, "uniform block"); + } else { + error(line, "only uniform interface blocks are supported", blockName.c_str(), ""); + recover(); + + return; + } + + // Build and add the interface block as a new type named blockName + + TType* blockType = new TType(&typeList, blockName, qualifier.qualifier.storage); + TVariable* userTypeDef = new TVariable(&blockName, *blockType, true); + if (! symbolTable.insert(*userTypeDef)) { + error(line, "redefinition", blockName.c_str(), "block name"); + recover(); + + return; + } + + // TODO: semantics: check for qualifiers that don't belong within a block + for (unsigned int member = 0; member < typeList.size(); ++member) { + //printf("%s: %s\n", typeList[member].type->getFieldName().c_str(), typeList[member].type->getCompleteString().c_str()); + } + + // Add the variable, as anonymous or named instanceName + + // make an anonymous variable if no name was provided + if (! instanceName) + instanceName = new TString(""); + + TVariable* variable = new TVariable(instanceName, *blockType); + + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str(), ""); + delete variable; + recover(); + + return; + } +} + // // This function returns the tree representation for the vector field(s) being accessed from contant vector. // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 13e33451..d0d189e5 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -122,7 +122,7 @@ struct TParseContext { bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason); bool globalQualifierFixAndErrorCheck(int line, TQualifier&, const TPublicType&); bool structQualifierErrorCheck(int line, const TPublicType& pType); - bool mergeQualifiersErrorCheck(int line, TPublicType& left, const TPublicType& right); + bool mergeQualifiersErrorCheck(int line, TPublicType& dst, const TPublicType& src, bool force); void setDefaultPrecision(int line, TPublicType&, TPrecisionQualifier); bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type); bool containsSampler(const TType& type); @@ -140,10 +140,12 @@ struct TParseContext { TIntermTyped* addConstructor(TIntermNode*, const TType&, TOperator, TFunction*, TSourceLoc); TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset); + void addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc); TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc); TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line); TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); + bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc); void requireProfile(int line, EProfileMask profileMask, const char *featureDesc); void requireStage(int line, EShLanguageMask languageMask, const char *featureDesc); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 6c84725f..25da7d74 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -406,7 +406,7 @@ postfix_expression } else if ($1->isMatrix()) { parseContext.error($2.line, "field selection not allowed on matrix", ".", ""); parseContext.recover(); - } else if ($1->getBasicType() == EbtStruct) { + } else if ($1->getBasicType() == EbtStruct || $1->getBasicType() == EbtBlock) { bool fieldFound = false; TTypeList* fields = $1->getType().getStruct(); if (fields == 0) { @@ -1184,15 +1184,15 @@ declaration $$ = 0; } | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE SEMICOLON { - // block + parseContext.addBlock($2.line, $1, *$2.string, *$4); $$ = 0; } | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { - // block + parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string); $$ = 0; } | type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE IDENTIFIER array_specifier SEMICOLON { - // block + parseContext.addBlock($2.line, $1, *$2.string, *$4, $6.string, $7.arraySizes); $$ = 0; } | type_qualifier SEMICOLON { @@ -1665,7 +1665,7 @@ type_qualifier if ($$.type == EbtVoid) $$.type = $2.type; - if (parseContext.mergeQualifiersErrorCheck($$.line, $$, $2)) + if (parseContext.mergeQualifiersErrorCheck($$.line, $$, $2, false)) parseContext.recover(); } ; @@ -2530,6 +2530,7 @@ precision_qualifier struct_specifier : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE { + // TODO: semantics: check for qualifiers that don't belong in a struct TType* structure = new TType($4, *$2.string); TVariable* userTypeDef = new TVariable($2.string, *structure, true); if (! parseContext.symbolTable.insert(*userTypeDef)) { @@ -2557,7 +2558,7 @@ struct_declaration_list for (unsigned int i = 0; i < $2->size(); ++i) { for (unsigned int j = 0; j < $$->size(); ++j) { if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) { - parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str()); + parseContext.error((*$2)[i].line, "duplicate member name:", "", (*$2)[i].type->getFieldName().c_str()); parseContext.recover(); } } @@ -2598,15 +2599,16 @@ struct_declaration $$ = $3; - if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) { + if (parseContext.voidErrorCheck($2.line, (*$3)[0].type->getFieldName(), $2)) + parseContext.recover(); + if (parseContext.mergeQualifiersErrorCheck($2.line, $2, $1, true)) parseContext.recover(); - } for (unsigned int i = 0; i < $$->size(); ++i) { // // Careful not to replace already know aspects of type, like array-ness // (*$$)[i].type->setElementType($2.type, $2.vectorSize, $2.matrixCols, $2.matrixRows, $2.userDef); - + (*$$)[i].type->getQualifier() = $2.qualifier; if ($2.arraySizes) (*$$)[i].type->setArraySizes($2.arraySizes); if ($2.userDef)