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