From 211cba242b6a3dc99d37abb62e8f3b0ae73ed98e Mon Sep 17 00:00:00 2001 From: John Kessenich <cepheus@frii.com> Date: Thu, 20 Jun 2013 22:54:40 +0000 Subject: [PATCH] Add grammar productions for the syntax "layout(...) uniform;" for setting global defaults. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@22112 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Test/300layout.vert | 2 +- glslang/MachineIndependent/ParseHelper.cpp | 153 +++++++++++++++------ glslang/MachineIndependent/ParseHelper.h | 10 +- glslang/MachineIndependent/glslang.y | 10 +- 4 files changed, 121 insertions(+), 54 deletions(-) diff --git a/Test/300layout.vert b/Test/300layout.vert index e8cba1538..361d82667 100644 --- a/Test/300layout.vert +++ b/Test/300layout.vert @@ -9,7 +9,7 @@ layout(LocatioN = 10) in s r[4]; // ERROR, no struct out vec4 pos; out vec3 color; -layout(shared, column_major, row_major) uniform mat4 badm4; // ERROR +layout(shared, column_major) uniform mat4 badm4; // ERROR layout(shared, column_major, row_major) uniform; // default is now shared and row_major layout(std140) uniform Transform { // layout of this block is std140 diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index a32ea21a3..9d6c23a35 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -81,10 +81,16 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E } } - defaultGlobalQualification.clear(); - defaultGlobalQualification.layoutMatrix = ElmColumnMajor; - defaultGlobalQualification.layoutPacking = ElpShared; - defaultGlobalQualification.layoutSlotLocation = 0; + globalUniformDefaults.clear(); + globalUniformDefaults.layoutMatrix = ElmColumnMajor; + globalUniformDefaults.layoutPacking = ElpShared; + globalUniformDefaults.layoutSlotLocation = 0; + + globalInputDefaults.clear(); + globalInputDefaults.layoutSlotLocation = 0; + + globalOutputDefaults.clear(); + globalOutputDefaults.layoutSlotLocation = 0; } // Get code that is not part of a shared symbol table, specific to this shader @@ -1541,12 +1547,7 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta if (profile == EEsProfile && arraySizes) arraySizeRequiredCheck(line, arraySizes->front()); - if (publicBlockType.basicType != EbtVoid) { - error(line, "interface blocks cannot be declared with a type", blockName->c_str(), ""); - - return; - } - if (publicBlockType.qualifier.storage == EvqUniform) { + if (currentBlockDefaults.storage == EvqUniform) { requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block"); profileRequires(line, EEsProfile, 300, 0, "uniform block"); } else { @@ -1558,9 +1559,9 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta // check for qualifiers and types that don't belong within a block for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier memberQualifier = typeList[member].type->getQualifier(); - if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != publicBlockType.qualifier.storage) + if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockDefaults.storage) error(line, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), ""); - if (publicBlockType.qualifier.storage == EvqUniform && memberQualifier.isInterpolation() || memberQualifier.isAuxillary()) + if (currentBlockDefaults.storage == EvqUniform && memberQualifier.isInterpolation() || memberQualifier.isAuxillary()) error(line, "member of uniform block cannot have an auxillary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), ""); TBasicType basicType = typeList[member].type->getBasicType(); @@ -1570,8 +1571,15 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta // Make default block qualification, and adjust the member qualifications - TQualifier defaultQualification = defaultGlobalQualification; - mergeLayoutQualifiers(line, defaultQualification, publicBlockType.qualifier); + TQualifier defaultQualification; + switch (currentBlockDefaults.storage) { + case EvqUniform: defaultQualification = globalUniformDefaults; break; + case EvqIn: defaultQualification = globalInputDefaults; break; + case EvqOut: defaultQualification = globalOutputDefaults; break; + default: defaultQualification.clear(); break; + } + + mergeLayoutQualifiers(line, defaultQualification, currentBlockDefaults); for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier memberQualification = defaultQualification; mergeLayoutQualifiers(line, memberQualification, typeList[member].type->getQualifier()); @@ -1580,7 +1588,7 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta // Build and add the interface block as a new type named blockName - TType blockType(&typeList, *blockName, publicBlockType.qualifier.storage); + TType blockType(&typeList, *blockName, currentBlockDefaults.storage); if (arraySizes) blockType.setArraySizes(arraySizes); blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking; @@ -1624,12 +1632,13 @@ void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, const qualifier.isInterpolation() || qualifier.storage != EvqTemporary || qualifier.precision != EpqNone) { - error(line, "cannot add this qualifier to an existing variable", identifier.c_str(), ""); + error(line, "cannot add storage, auxillary, memory, interpolation, or precision qualifier to an existing variable", identifier.c_str(), ""); return; } - variable->getType().getQualifier().invariant = true; + if (qualifier.invariant) + variable->getType().getQualifier().invariant = true; } void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, TIdentifierList& identifiers) @@ -1638,6 +1647,88 @@ void TParseContext::addQualifierToExisting(int line, TQualifier qualifier, TIden addQualifierToExisting(line, qualifier, *identifiers[i]); } +void TParseContext::updateQualifierDefaults(TQualifier qualifier) +{ + switch (qualifier.storage) { + case EvqUniform: + if (qualifier.layoutMatrix != ElmNone) + globalUniformDefaults.layoutMatrix = qualifier.layoutMatrix; + if (qualifier.layoutPacking != ElpNone) + globalUniformDefaults.layoutPacking = qualifier.layoutPacking; + break; + case EvqIn: + if (qualifier.hasLocation()) + globalInputDefaults.layoutSlotLocation = qualifier.layoutSlotLocation; + break; + case EvqOut: + if (qualifier.hasLocation()) + globalOutputDefaults.layoutSlotLocation = qualifier.layoutSlotLocation; + break; + default: + // error handling should be done by callers of this function + break; + } +} + +void TParseContext::updateQualifierDefaults(int line, TQualifier qualifier) +{ + if (qualifier.isAuxillary() || + qualifier.isMemory() || + qualifier.isInterpolation() || + qualifier.precision != EpqNone) + error(line, "cannot use auxillary, memory, interpolation, or precision qualifier in a standalone qualifier", "", ""); + + switch (qualifier.storage) { + case EvqUniform: + case EvqIn: + case EvqOut: + break; + default: + error(line, "standalone qualifier requires 'uniform', 'in', or 'out' storage qualification", "", ""); + return; + } + + updateQualifierDefaults(qualifier); +} + +void TParseContext::updateTypedDefaults(int line, TQualifier qualifier, const TString* id) +{ + bool cantHaveId = false; + + if (! id) { + if (qualifier.hasLayout()) + warn(line, "cannot set qualifier defaults when using a type and no identifier", "", ""); + + return; + } + + if (qualifier.storage == EvqUniform) { + if (qualifier.layoutMatrix != ElmNone) + error(line, "cannot specify matrix layout on a variable declaration", id->c_str(), ""); + if (qualifier.layoutPacking != ElpNone) + error(line, "cannot specify packing on a variable declaration", id->c_str(), ""); + } else if (qualifier.storage == EvqVaryingIn) { + if (qualifier.hasLayout() && language != EShLangVertex) { + error(line, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), ""); + } + } else if (qualifier.storage == EvqVaryingOut) { + if (qualifier.hasLayout() && language != EShLangFragment) { + error(line, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), ""); + } + } else { + if (qualifier.layoutMatrix != ElmNone || + qualifier.layoutPacking != ElpNone) + error(line, "layout qualifiers for matrix layout and packing only apply to uniform blocks", id->c_str(), ""); + else if (qualifier.hasLocation()) + error(line, "location qualifiers only appy to uniform, in, or out storage qualifiers", id->c_str(), ""); + } + + if (cantHaveId) + error(line, "cannot set global layout qualifiers on uniform variable, use just 'uniform' or a block", id->c_str(), ""); + + updateQualifierDefaults(qualifier); +} + // // 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, @@ -1697,34 +1788,6 @@ TIntermNode* TParseContext::addSwitch(int line, TIntermTyped* expression, TInter return switchNode; } -void TParseContext::updateDefaults(int line, const TPublicType& publicType, const TString* id) -{ - bool cantHaveId = false; - TQualifier qualifier = publicType.qualifier; - - if (qualifier.storage == EvqUniform) { - if (qualifier.layoutMatrix != ElmNone) { - cantHaveId = true; - defaultGlobalQualification.layoutMatrix = qualifier.layoutMatrix; - } - if (qualifier.layoutPacking != ElpNone) { - cantHaveId = true; - defaultGlobalQualification.layoutPacking = qualifier.layoutPacking; - } - } else if (qualifier.storage == EvqVaryingIn) { - if (qualifier.hasLayout() && language != EShLangVertex) { - error(line, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), ""); - } - } else if (qualifier.storage == EvqVaryingOut) { - if (qualifier.hasLayout() && language != EShLangFragment) { - error(line, "can only use location layout qualifier on a vertex input or fragment output", id->c_str(), ""); - } - } - - if (cantHaveId && id) - error(line, "cannot set global layout qualifiers on uniform variable, use just 'uniform' or a block", id->c_str(), ""); -} - // // 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 04a80b59d..43ec8fe54 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -93,11 +93,13 @@ struct TParseContext { TPrecisionQualifier defaultPrecision[EbtNumTypes]; static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2)); // see computeSamplerTypeIndex() TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex]; - TQualifier defaultGlobalQualification; TString HashErrMsg; bool AfterEOF; const TString* blockName; - TPublicType publicBlockType; + TQualifier globalUniformDefaults; + TQualifier globalInputDefaults; + TQualifier globalOutputDefaults; + TQualifier currentBlockDefaults; void initializeExtensionBehavior(); const char* getPreamble(); @@ -156,9 +158,11 @@ struct TParseContext { 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 updateQualifierDefaults(TQualifier); + void updateQualifierDefaults(int line, TQualifier); + void updateTypedDefaults(int line, TQualifier, const TString* id); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body); - void updateDefaults(int line, const TPublicType&, const TString* id); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc); TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc); TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 42e0635b6..39003818c 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -1119,7 +1119,7 @@ declaration $$ = 0; } | type_qualifier SEMICOLON { - // setting defaults + parseContext.updateQualifierDefaults($1.line, $1.qualifier); $$ = 0; } | type_qualifier IDENTIFIER SEMICOLON { @@ -1137,7 +1137,7 @@ block_structure : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.line); } struct_declaration_list RIGHT_BRACE { --parseContext.structNestingLevel; parseContext.blockName = $2.string; - parseContext.publicBlockType = $1; + parseContext.currentBlockDefaults = $1.qualifier; $$.line = $1.line; $$.typeList = $5; } @@ -1395,7 +1395,7 @@ single_declaration : fully_specified_type { $$.type = $1; $$.intermAggregate = 0; - parseContext.updateDefaults($1.line, $$.type, 0); + parseContext.updateTypedDefaults($1.line, $$.type.qualifier, 0); } | fully_specified_type IDENTIFIER { $$.intermAggregate = 0; @@ -1404,7 +1404,7 @@ single_declaration parseContext.nonInitConstCheck($2.line, *$2.string, $$.type); parseContext.nonInitCheck($2.line, *$2.string, $$.type); - parseContext.updateDefaults($2.line, $$.type, $2.string); + parseContext.updateTypedDefaults($2.line, $$.type.qualifier, $2.string); } | fully_specified_type IDENTIFIER array_specifier { $$.intermAggregate = 0; @@ -1419,7 +1419,7 @@ single_declaration TVariable* variable; parseContext.arrayCheck($3.line, *$2.string, $1, variable); } - parseContext.updateDefaults($2.line, $$.type, $2.string); + parseContext.updateTypedDefaults($2.line, $$.type.qualifier, $2.string); } | fully_specified_type IDENTIFIER array_specifier EQUAL initializer { $$.intermAggregate = 0; -- GitLab