diff --git a/Test/420.frag b/Test/420.frag new file mode 100644 index 0000000000000000000000000000000000000000..98ddf3d2e52933e38e0547f5272e105b63fe15af --- /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 0000000000000000000000000000000000000000..281614d76829180a5e8ea816efd1e61657710c29 --- /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 d4438e8b38716597639de0850fd4aa7a5de2a332..7e0b41d8d04c711f26b7afac2b68459a24c2dbc4 100644 --- a/Test/baseResults/specExamples.frag.out +++ b/Test/baseResults/specExamples.frag.out @@ -16,11 +16,9 @@ ERROR: 0:100: 'local_size_x' : there is no such layout identifier for this stage 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:226: 'in' : not allowed in nested scope 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 @@ Requested GL_3DL_array_objects 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 @@ Requested GL_3DL_array_objects 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 b19db13664c7d1628b01b638964c4ba124e2bc7c..d76f970b046072f594fef711c5820394ffb7a989 100644 --- a/Test/testlist +++ b/Test/testlist @@ -53,6 +53,7 @@ tokenLength.vert 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 7bf06a401bebb5080519dd56c329069f7c9c1ff3..6efc3f13d5637660886c089f02dc1be0932b72c0 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -305,6 +305,16 @@ enum TLayoutFormat { ElfCount }; +enum TLayoutDepth { + EldNone, + EldAny, + EldGreater, + EldLess, + EldUnchanged, + + EldCount +}; + class TQualifier { public: void clear() @@ -645,6 +655,16 @@ public: 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 @@ struct TShaderQualifiers { bool pointMode; int localSize[3]; // compute shader bool earlyFragmentTests; // fragment input + TLayoutDepth layoutDepth; void init() { @@ -718,6 +739,7 @@ struct TShaderQualifiers { 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 @@ struct TShaderQualifiers { } if (src.earlyFragmentTests) earlyFragmentTests = true; + if (src.layoutDepth) + layoutDepth = src.layoutDepth; } }; @@ -1160,10 +1184,8 @@ public: 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 a1a90b777e2c0ebea89492509b235bd91d60d00d..b4393de336f3c7a58f3b282fac455b930f3f0b84 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -2565,8 +2565,14 @@ TSymbol* TParseContext::redeclareBuiltinVariable(TSourceLoc loc, const TString& 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 @@ void TParseContext::finalErrorCheck() // 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 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType, 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 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier, 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 f711225ff2834c338899d39e7c8fad60dbaa44e2..9211b1e14e34e281e1615265dc0687e24797c1f4 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -621,6 +621,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) 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 9361bdc45b97a73f35d48ee72ad880a123c95c99..8efe224101eb9352172b3b627413f0f08d9aec36 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -83,6 +83,11 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) 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 54aa6dd7c36a22a5f46048f4e06004df7d2d9916..8fdc0e836362984cdcd13f5418b5d62e9570f389 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -112,7 +112,7 @@ public: 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 @@ public: 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 @@ protected: bool pointMode; int localSize[3]; bool earlyFragmentTests; + TLayoutDepth depthLayout; bool xfbMode; typedef std::list<TCall> TGraph;