Implement conservative depth layout qualifiers.  Based partly on a submission.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27758 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/Test/420.frag b/Test/420.frag
new file mode 100644
index 0000000..98ddf3d
--- /dev/null
+++ b/Test/420.frag
@@ -0,0 +1,12 @@
+#version 420 core
+
+layout(depth_any) out float gl_FragDepth;
+layout(depth_greater) out float gl_FragDepth; // ERROR: redeclaration with different qualifier
+
+void main()
+{
+    gl_FragDepth = 0.3;
+}
+
+layout(depth_less) in float depth; // ERROR: depth_less only applies to gl_FragDepth
+layout(depth_any) out float gl_FragDepth;  // ERROR, done after use
diff --git a/Test/baseResults/420.frag.out b/Test/baseResults/420.frag.out
new file mode 100644
index 0000000..281614d
--- /dev/null
+++ b/Test/baseResults/420.frag.out
@@ -0,0 +1,42 @@
+420.frag

+Warning, version 420 is not yet complete; most version-specific features are present, but some are missing.

+ERROR: 0:4: 'redeclaration' : all redeclarations must use the same depth layout on gl_FragDepth

+ERROR: 0:11: 'layout qualifier' : can only apply depth layout to gl_FragDepth 

+ERROR: 0:12: 'gl_FragDepth' : cannot redeclare after use 

+ERROR: 3 compilation errors.  No code generated.

+

+

+Shader version: 420

+using depth_any

+ERROR: node is still EOpNull!

+0:6  Function Definition: main( (void)

+0:6    Function Parameters: 

+0:8    Sequence

+0:8      move second child to first child (float)

+0:8        'gl_FragDepth' (gl_FragDepth float)

+0:8        Constant:

+0:8          0.300000

+0:?   Linker Objects

+0:?     'gl_FragDepth' (gl_FragDepth float)

+0:?     'gl_FragDepth' (gl_FragDepth float)

+0:?     'depth' (smooth in float)

+

+

+Linked fragment stage:

+

+

+Shader version: 420

+using depth_any

+ERROR: node is still EOpNull!

+0:6  Function Definition: main( (void)

+0:6    Function Parameters: 

+0:8    Sequence

+0:8      move second child to first child (float)

+0:8        'gl_FragDepth' (gl_FragDepth float)

+0:8        Constant:

+0:8          0.300000

+0:?   Linker Objects

+0:?     'gl_FragDepth' (gl_FragDepth float)

+0:?     'gl_FragDepth' (gl_FragDepth float)

+0:?     'depth' (smooth in float)

+

diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out
index d4438e8..7e0b41d 100644
--- a/Test/baseResults/specExamples.frag.out
+++ b/Test/baseResults/specExamples.frag.out
@@ -16,11 +16,9 @@
 ERROR: 0:102: 'color' : redefinition 

 ERROR: 0:103: 'index' : there is no such layout identifier for this stage taking an assigned value 

 ERROR: 0:104: 'location' : overlapping use of location 3

-ERROR: 0:106: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 

-ERROR: 0:112: 'depth_any' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 

-ERROR: 0:115: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 

-ERROR: 0:118: 'depth_less' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 

-ERROR: 0:121: 'depth_unchanged' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 

+ERROR: 0:112: 'redeclaration' : all redeclarations must use the same depth layout on gl_FragDepth

+ERROR: 0:118: 'redeclaration' : all redeclarations must use the same depth layout on gl_FragDepth

+ERROR: 0:121: 'redeclaration' : all redeclarations must use the same depth layout on gl_FragDepth

 ERROR: 0:150: 'constructor' : constructing from a non-dereferenced array 

 ERROR: 0:150: '=' :  cannot convert from 'const float' to '3-element array of 4-component vector of float'

 ERROR: 0:152: 'constructor' :  cannot convert parameter 1 from 'const 2-element array of 4-component vector of float' to '4-component vector of float'

@@ -45,7 +43,7 @@
 ERROR: 0:227: 'in' : not allowed in nested scope 

 ERROR: 0:228: 'in' : not allowed in nested scope 

 ERROR: 0:232: 'out' : not allowed in nested scope 

-ERROR: 45 compilation errors.  No code generated.

+ERROR: 43 compilation errors.  No code generated.

 

 

 Shader version: 430

@@ -53,6 +51,7 @@
 gl_FragCoord pixel center is integer

 gl_FragCoord origin is upper left

 using early_fragment_tests

+using depth_greater

 ERROR: node is still EOpNull!

 0:5  Sequence

 0:5    move second child to first child (int)

@@ -306,6 +305,7 @@
 gl_FragCoord pixel center is integer

 gl_FragCoord origin is upper left

 using early_fragment_tests

+using depth_greater

 ERROR: node is still EOpNull!

 0:5  Sequence

 0:5    move second child to first child (int)

diff --git a/Test/testlist b/Test/testlist
index b19db13..d76f970 100644
--- a/Test/testlist
+++ b/Test/testlist
@@ -53,6 +53,7 @@
 110scope.vert
 300scope.vert
 400.frag
+420.frag
 420.vert
 420.geom
 420_size_gl_in.geom
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 7bf06a4..6efc3f1 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -305,6 +305,16 @@
     ElfCount
 };
 
+enum TLayoutDepth {
+    EldNone,
+    EldAny,
+    EldGreater,
+    EldLess,
+    EldUnchanged,
+    
+    EldCount
+};
+
 class TQualifier {
 public:
     void clear()
@@ -645,6 +655,16 @@
         default:              return "none";
         }
     }
+    static const char* getLayoutDepthString(TLayoutDepth d)
+    {
+        switch (d) {
+        case EldAny:       return "depth_any";
+        case EldGreater:   return "depth_greater";
+        case EldLess:      return "depth_less";
+        case EldUnchanged: return "depth_unchanged";
+        default:           return "none";
+        }
+    }
     static const char* getGeometryString(TLayoutGeometry geometry)
     {
         switch (geometry) {
@@ -703,6 +723,7 @@
     bool pointMode;
     int localSize[3];         // compute shader
     bool earlyFragmentTests;  // fragment input
+    TLayoutDepth layoutDepth;
 
     void init()
     {
@@ -718,6 +739,7 @@
         localSize[1] = 1;
         localSize[2] = 1;
         earlyFragmentTests = false;
+        layoutDepth = EldNone;
     }
 
     // Merge in characteristics from the 'src' qualifier.  They can override when
@@ -746,6 +768,8 @@
         }
         if (src.earlyFragmentTests)
             earlyFragmentTests = true;
+        if (src.layoutDepth)
+            layoutDepth = src.layoutDepth;
     }
 };
 
@@ -1160,10 +1184,8 @@
                     p += snprintf(p, end - p, "offset=%d ", qualifier.layoutOffset);
                 if (qualifier.hasAlign())
                     p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
-
                 if (qualifier.hasFormat())
                     p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat));
-
                 if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset())
                     p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
                 if (qualifier.hasXfbOffset())
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index a1a90b7..b4393de 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -2565,8 +2565,14 @@
                 error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
             if (qualifier.storage != EvqVaryingOut)
                 error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
-            // TODO 4.2: gl_FragDepth redeclaration
-        }        
+            if (publicType.layoutDepth != EldNone) {
+                if (intermediate.inIoAccessed("gl_FragDepth"))
+                    error(loc, "cannot redeclare after use", "gl_FragDepth", "");
+                if (! intermediate.setDepth(publicType.layoutDepth))
+                    error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str());
+            }
+
+        }
         // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
 
         return symbol;
@@ -2965,8 +2971,8 @@
 // Layout qualifier stuff.
 //
 
-// Put the id's layout qualification into the public type.  This is before we know any
-// type information for error checking.
+// Put the id's layout qualification into the public type, for qualifiers not having a number set.
+// This is before we know any type information for error checking.
 void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType, TString& id)
 {
     std::transform(id.begin(), id.end(), id.begin(), ::tolower);
@@ -3105,12 +3111,20 @@
             publicType.shaderQualifiers.earlyFragmentTests = true;
             return;
         }
+        for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) {
+            if (id == TQualifier::getLayoutDepthString(depth)) {
+                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier");
+                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 0, "depth layout qualifier");
+                publicType.shaderQualifiers.layoutDepth = depth;
+                return;
+            }
+        }
     }
     error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
 }
 
-// Put the id's layout qualifier value into the public type.  This is before we know any
-// type information for error checking.
+// Put the id's layout qualifier value into the public type, for qualifiers having a number set.
+// This is before we know any type information for error checking.
 void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType, TString& id, const TIntermTyped* node)
 {
     const char* feature = "layout-id value";
@@ -3742,6 +3756,8 @@
 
     if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
         error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
+    if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.layoutDepth != EldNone)
+        error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
 
     // Check for redeclaration of built-ins and/or attempting to declare a reserved name
     bool newDeclaration = false;    // true if a new entry gets added to the symbol table
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index f711225..9211b1e 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -621,6 +621,8 @@
             infoSink.debug << "gl_FragCoord origin is upper left\n";
         if (earlyFragmentTests)
             infoSink.debug << "using early_fragment_tests\n";
+        if (depthLayout != EldNone)
+            infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
         break;
 
     case EShLangCompute:
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 9361bdc..8efe224 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -83,6 +83,11 @@
     if (! earlyFragmentTests)

         earlyFragmentTests = unit.earlyFragmentTests;

 

+    if (depthLayout == EldNone)

+        depthLayout = unit.depthLayout;

+    else if (depthLayout != unit.depthLayout)

+        error(infoSink, "Contradictory depth layouts");

+

     if (inputPrimitive == ElgNone)

         inputPrimitive = unit.inputPrimitive;

     else if (inputPrimitive != unit.inputPrimitive)

diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 54aa6dd..8fdc0e8 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -112,7 +112,7 @@
     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v), 
         numMains(0), numErrors(0), recursive(false),
         invocations(0), vertices(0), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false),
-        vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), xfbMode(false)
+        vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), xfbMode(false)
     {
         localSize[0] = 1;
         localSize[1] = 1;
@@ -250,6 +250,14 @@
     bool getPixelCenterInteger() const { return pixelCenterInteger; }
     void setEarlyFragmentTests() { earlyFragmentTests = true; }
     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
+    bool setDepth(TLayoutDepth d)
+    {
+        if (depthLayout != EldNone)
+            return depthLayout == d;
+        depthLayout = d;
+        return true;
+    }
+    TLayoutDepth getDepth() const { return depthLayout; }
 
     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
     void merge(TInfoSink&, TIntermediate&);
@@ -304,6 +312,7 @@
     bool pointMode;
     int localSize[3];
     bool earlyFragmentTests;
+    TLayoutDepth depthLayout;
     bool xfbMode;
 
     typedef std::list<TCall> TGraph;