From bcd79fe5a301424ba7aed1a512edafbfdd43b0fe Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Wed, 10 Apr 2013 22:26:56 +0000
Subject: [PATCH] Implement default layout qualifiers at global and block
 levels with proper inheritance.  Also add more error checking of qualifiers.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@21107 e7fa87d3-cd2b-0410-9028-fcbf551c1848
---
 Test/300layout.vert                        |  6 ++
 glslang/MachineIndependent/ParseHelper.cpp | 83 +++++++++++++++++-----
 glslang/MachineIndependent/ParseHelper.h   |  4 +-
 glslang/MachineIndependent/glslang.y       |  8 ++-
 glslang/MachineIndependent/intermOut.cpp   |  4 +-
 5 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/Test/300layout.vert b/Test/300layout.vert
index 60ef58514..7abbed31a 100644
--- a/Test/300layout.vert
+++ b/Test/300layout.vert
@@ -12,6 +12,8 @@ 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
+    centroid float badf;  // ERROR
+    in float badg;        // ERROR
 } tblock;
 
 uniform T2 { // layout of this block is shared
@@ -26,6 +28,10 @@ layout(column_major) uniform T3 { // shared and column_major
     int b;  // ERROR, redefinition (needs to be last member of block for testing, following members are skipped)
 };
 
+out badout {  // ERROR
+    float f;
+};
+
 void main()
 {
     pos = p * (tblock.M1 + tblock.M2 + M4 + M3 + t2m);
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 3f8df1585..dc69bb92d 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -70,6 +70,11 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E
             error(1, "INTERNAL ERROR", "unexpected language", "");
         }
     }
+
+    defaultGlobalQualification.clear();
+    defaultGlobalQualification.layoutMatrix = ElmColumnMajor;
+    defaultGlobalQualification.layoutPacking = ElpShared;
+    defaultGlobalQualification.layoutSlotLocation = 0;
 }
 
 ///////////////////////////////////////////////////////////////////////
@@ -750,7 +755,7 @@ bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& dst, const
         dst.qualifier.precision = src.qualifier.precision;
 
     // Layout qualifiers
-    mergeLayoutQualifiers(line, dst, src);
+    mergeLayoutQualifiers(line, dst.qualifier, src.qualifier);
 
     // other qualifiers
     #define MERGE_SINGLETON(field) bad |= dst.qualifier.field && src.qualifier.field; dst.qualifier.field |= src.qualifier.field;
@@ -1133,16 +1138,16 @@ void TParseContext::setLayoutQualifier(int line, TPublicType& publicType, TStrin
 }
 
 // Merge any layout qualifier information from src into dst, leaving everything else in dst alone
-void TParseContext::mergeLayoutQualifiers(int line, TPublicType& dst, const TPublicType& src)
+void TParseContext::mergeLayoutQualifiers(int line, TQualifier& dst, const TQualifier& src)
 {
-    if (src.qualifier.layoutMatrix != ElmNone)
-        dst.qualifier.layoutMatrix = src.qualifier.layoutMatrix;
+    if (src.layoutMatrix != ElmNone)
+        dst.layoutMatrix = src.layoutMatrix;
 
-    if (src.qualifier.layoutPacking != ElpNone)
-        dst.qualifier.layoutPacking = src.qualifier.layoutPacking;
+    if (src.layoutPacking != ElpNone)
+        dst.layoutPacking = src.layoutPacking;
 
-    if (src.qualifier.hasLocation())
-        dst.qualifier.layoutSlotLocation = src.qualifier.layoutSlotLocation;
+    if (src.hasLocation())
+        dst.layoutSlotLocation = src.layoutSlotLocation;
 }
 
 /////////////////////////////////////////////////////////////////////////////////
@@ -1464,7 +1469,7 @@ TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& typ
 //
 // 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)
+void TParseContext::addBlock(int line, TPublicType& publicType, const TString& blockName, TTypeList& typeList, const TString* instanceName, TArraySizes arraySizes)
 {
     // First, error checks
 
@@ -1478,13 +1483,13 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
 
         return;
     }
-    if (qualifier.basicType != EbtVoid) {
+    if (publicType.basicType != EbtVoid) {
         error(line, "interface blocks cannot be declared with a type", blockName.c_str(), "");
         recover();
 
         return;
     }
-    if (qualifier.qualifier.storage == EvqUniform) {
+    if (publicType.qualifier.storage == EvqUniform) {
         requireProfile(line, (EProfileMask)(~ENoProfileMask), "uniform block");
         profileRequires(line, EEsProfile, 300, 0, "uniform block");
     } else {
@@ -1494,9 +1499,36 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
         return;
     }
 
+    // check for qualifiers 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 != publicType.qualifier.storage) {
+            error(line, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), "");
+            recover();
+        }
+        if (publicType.qualifier.storage == EvqUniform) {
+            if (memberQualifier.isInterpolation() || memberQualifier.isAuxillary()) {
+                error(line, "member of uniform block cannot have an auxillary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), "");
+                recover();
+            }
+        }
+    }
+
+    // Make default block qualification, and adjust the member qualifications
+
+    TQualifier defaultQualification = defaultGlobalQualification;
+    mergeLayoutQualifiers(line, defaultQualification, publicType.qualifier);
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier memberQualification = defaultQualification;
+        mergeLayoutQualifiers(line, memberQualification, typeList[member].type->getQualifier());
+        typeList[member].type->getQualifier() = memberQualification;
+    }
+
     // Build and add the interface block as a new type named blockName
 
-    TType blockType(&typeList, blockName, qualifier.qualifier.storage);
+    TType blockType(&typeList, blockName, publicType.qualifier.storage);
+    blockType.getQualifier().layoutPacking = defaultQualification.layoutPacking;
     TVariable* userTypeDef = new TVariable(&blockName, blockType, true);
     if (! symbolTable.insert(*userTypeDef)) {
         error(line, "redefinition", blockName.c_str(), "block name");
@@ -1505,11 +1537,6 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
         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
@@ -1528,6 +1555,28 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
     }
 }
 
+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;
+        }
+    }
+
+    if (cantHaveId && id) {
+        error(line, "cannot set global layout qualifiers on uniform variable, use just 'uniform' or a block", id->c_str(), "");
+        recover();
+    }
+}
+
 //
 // 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 d0d189e56..69504130d 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -91,6 +91,7 @@ struct TParseContext {
 
     struct TPragma contextPragma;
     TPrecisionQualifier defaultPrecision[EbtNumTypes];
+    TQualifier defaultGlobalQualification;
 	TString HashErrMsg;
     bool AfterEOF;
 
@@ -132,7 +133,7 @@ struct TParseContext {
 
     void setLayoutQualifier(int line, TPublicType&, TString&);
     void setLayoutQualifier(int line, TPublicType&, TString&, int);
-    void mergeLayoutQualifiers(int line, TPublicType& dest, const TPublicType& src);
+    void mergeLayoutQualifiers(int line, TQualifier& dest, const TQualifier& src);
 
     const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
     bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
@@ -141,6 +142,7 @@ struct TParseContext {
     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);
+    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 954e5bd24..5ac46d723 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -234,7 +234,7 @@ variable_identifier
             unionArray->setUConst(anon->getMemberNumber());
             TIntermTyped* constNode = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), $1.line);
 
-            $$ = parseContext.intermediate.addIndex(EOpIndexDirect, container, constNode, $1.line);
+            $$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, container, constNode, $1.line);
             $$->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
         } else {
             const TVariable* variable = symbol ? symbol->getAsVariable() : 0;
@@ -1494,6 +1494,7 @@ single_declaration
     : fully_specified_type {
         $$.type = $1;
         $$.intermAggregate = 0;
+        parseContext.updateDefaults($1.line, $$.type, 0);
     }
     | fully_specified_type IDENTIFIER {
         $$.intermAggregate = 0;
@@ -1504,6 +1505,8 @@ single_declaration
 
         if (parseContext.nonInitErrorCheck($2.line, *$2.string, $$.type))
             parseContext.recover();
+        
+        parseContext.updateDefaults($2.line, $$.type, $2.string);
     }
     | fully_specified_type IDENTIFIER array_specifier {
         $$.intermAggregate = 0;
@@ -1520,6 +1523,7 @@ single_declaration
             if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable))
                 parseContext.recover();
         }
+        parseContext.updateDefaults($2.line, $$.type, $2.string);
     }
     | fully_specified_type IDENTIFIER array_specifier EQUAL initializer {
         $$.intermAggregate = 0;
@@ -1647,7 +1651,7 @@ layout_qualifier_id_list
     }
     | layout_qualifier_id_list COMMA layout_qualifier_id {
         $$ = $1;
-        parseContext.mergeLayoutQualifiers($2.line, $$, $3);
+        parseContext.mergeLayoutQualifiers($2.line, $$.qualifier, $3.qualifier);
     }
 
 layout_qualifier_id
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 982608463..ace815422 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -119,7 +119,9 @@ bool OutputBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it
 
     case EOpIndexDirect:   out.debug << "direct index";   break;
     case EOpIndexIndirect: out.debug << "indirect index"; break;
-    case EOpIndexDirectStruct:   out.debug << "direct index for structure";   break;
+    case EOpIndexDirectStruct:
+        out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getUnionArrayPointer()->getIConst()].type->getFieldName();
+        out.debug << ": direct index for structure";      break;
     case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
 
     case EOpAdd:    out.debug << "add";                     break;
-- 
GitLab