Przeglądaj źródła

Add SPV_AMD_shader_early_and_late_fragment_tests

dwang102 3 lat temu
rodzic
commit
070863af69

+ 1 - 0
SPIRV/GLSL.ext.KHR.h

@@ -53,5 +53,6 @@ static const char* const E_SPV_KHR_terminate_invocation         = "SPV_KHR_termi
 static const char* const E_SPV_KHR_workgroup_memory_explicit_layout = "SPV_KHR_workgroup_memory_explicit_layout";
 static const char* const E_SPV_KHR_subgroup_uniform_control_flow = "SPV_KHR_subgroup_uniform_control_flow";
 static const char* const E_SPV_KHR_fragment_shader_barycentric = "SPV_KHR_fragment_shader_barycentric";
+static const char* const E_SPV_AMD_shader_early_and_late_fragment_tests = "SPV_AMD_shader_early_and_late_fragment_tests";
 
 #endif  // #ifndef GLSLextKHR_H

+ 23 - 0
SPIRV/GlslangToSpv.cpp

@@ -1623,6 +1623,12 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
         if (glslangIntermediate->getEarlyFragmentTests())
             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
 
+        if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD())
+        {
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyAndLateFragmentTestsAMD);
+            builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests);
+        }
+
         if (glslangIntermediate->getPostDepthCoverage()) {
             builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage);
             builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage);
@@ -1632,6 +1638,9 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
         if (glslangIntermediate->isDepthReplacing())
             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
 
+        if (glslangIntermediate->isStencilReplacing())
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT);
+
 #ifndef GLSLANG_WEB
 
         switch(glslangIntermediate->getDepth()) {
@@ -1640,6 +1649,20 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
         case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break;
         default:                    mode = spv::ExecutionModeMax;            break;
         }
+
+        if (mode != spv::ExecutionModeMax)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+
+        switch (glslangIntermediate->getStencil()) {
+        case glslang::ElsRefUnchangedFrontAMD:  mode = spv::ExecutionModeStencilRefUnchangedFrontAMD; break;
+        case glslang::ElsRefGreaterFrontAMD:    mode = spv::ExecutionModeStencilRefGreaterFrontAMD;   break;
+        case glslang::ElsRefLessFrontAMD:       mode = spv::ExecutionModeStencilRefLessFrontAMD;      break;
+        case glslang::ElsRefUnchangedBackAMD:   mode = spv::ExecutionModeStencilRefUnchangedBackAMD;  break;
+        case glslang::ElsRefGreaterBackAMD:     mode = spv::ExecutionModeStencilRefGreaterBackAMD;    break;
+        case glslang::ElsRefLessBackAMD:        mode = spv::ExecutionModeStencilRefLessBackAMD;       break;
+        default:                       mode = spv::ExecutionModeMax;                         break;
+        }
+
         if (mode != spv::ExecutionModeMax)
             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
         switch (glslangIntermediate->getInterlockOrdering()) {

+ 24 - 20
SPIRV/doc.cpp

@@ -173,28 +173,32 @@ const char* ExecutionModeString(int mode)
     case 31: return "ContractionOff";
     case 32: return "Bad";
 
-    case ExecutionModeInitializer:              return "Initializer";
-    case ExecutionModeFinalizer:                return "Finalizer";
-    case ExecutionModeSubgroupSize:             return "SubgroupSize";
-    case ExecutionModeSubgroupsPerWorkgroup:    return "SubgroupsPerWorkgroup";
-    case ExecutionModeSubgroupsPerWorkgroupId:  return "SubgroupsPerWorkgroupId";
-    case ExecutionModeLocalSizeId:              return "LocalSizeId";
-    case ExecutionModeLocalSizeHintId:          return "LocalSizeHintId";
-
-    case ExecutionModePostDepthCoverage:        return "PostDepthCoverage";
-    case ExecutionModeDenormPreserve:           return "DenormPreserve";
-    case ExecutionModeDenormFlushToZero:        return "DenormFlushToZero";
-    case ExecutionModeSignedZeroInfNanPreserve: return "SignedZeroInfNanPreserve";
-    case ExecutionModeRoundingModeRTE:          return "RoundingModeRTE";
-    case ExecutionModeRoundingModeRTZ:          return "RoundingModeRTZ";
-    case ExecutionModeStencilRefReplacingEXT:   return "StencilRefReplacingEXT";
+    case ExecutionModeInitializer:                   return "Initializer";
+    case ExecutionModeFinalizer:                     return "Finalizer";
+    case ExecutionModeSubgroupSize:                  return "SubgroupSize";
+    case ExecutionModeSubgroupsPerWorkgroup:         return "SubgroupsPerWorkgroup";
+    case ExecutionModeSubgroupsPerWorkgroupId:       return "SubgroupsPerWorkgroupId";
+    case ExecutionModeLocalSizeId:                   return "LocalSizeId";
+    case ExecutionModeLocalSizeHintId:               return "LocalSizeHintId";
+
+    case ExecutionModePostDepthCoverage:             return "PostDepthCoverage";
+    case ExecutionModeDenormPreserve:                return "DenormPreserve";
+    case ExecutionModeDenormFlushToZero:             return "DenormFlushToZero";
+    case ExecutionModeSignedZeroInfNanPreserve:      return "SignedZeroInfNanPreserve";
+    case ExecutionModeRoundingModeRTE:               return "RoundingModeRTE";
+    case ExecutionModeRoundingModeRTZ:               return "RoundingModeRTZ";
+    case ExecutionModeEarlyAndLateFragmentTestsAMD:  return "EarlyAndLateFragmentTestsAMD";
+    case ExecutionModeStencilRefUnchangedFrontAMD:   return "StencilRefUnchangedFrontAMD";
+    case ExecutionModeStencilRefLessFrontAMD:        return "StencilRefLessFrontAMD";
+    case ExecutionModeStencilRefGreaterBackAMD:      return "StencilRefGreaterBackAMD";
+    case ExecutionModeStencilRefReplacingEXT:        return "StencilRefReplacingEXT";
     case ExecutionModeSubgroupUniformControlFlowKHR: return "SubgroupUniformControlFlow";
 
-    case ExecutionModeOutputLinesNV:            return "OutputLinesNV";
-    case ExecutionModeOutputPrimitivesNV:       return "OutputPrimitivesNV";
-    case ExecutionModeOutputTrianglesNV:        return "OutputTrianglesNV";
-    case ExecutionModeDerivativeGroupQuadsNV:   return "DerivativeGroupQuadsNV";
-    case ExecutionModeDerivativeGroupLinearNV:  return "DerivativeGroupLinearNV";
+    case ExecutionModeOutputLinesNV:                 return "OutputLinesNV";
+    case ExecutionModeOutputPrimitivesNV:            return "OutputPrimitivesNV";
+    case ExecutionModeOutputTrianglesNV:             return "OutputTrianglesNV";
+    case ExecutionModeDerivativeGroupQuadsNV:        return "DerivativeGroupQuadsNV";
+    case ExecutionModeDerivativeGroupLinearNV:       return "DerivativeGroupLinearNV";
 
     case ExecutionModePixelInterlockOrderedEXT:         return "PixelInterlockOrderedEXT";
     case ExecutionModePixelInterlockUnorderedEXT:       return "PixelInterlockUnorderedEXT";

+ 7 - 0
SPIRV/spirv.hpp

@@ -158,7 +158,14 @@ enum ExecutionMode {
     ExecutionModeSignedZeroInfNanPreserve = 4461,
     ExecutionModeRoundingModeRTE = 4462,
     ExecutionModeRoundingModeRTZ = 4463,
+    ExecutionModeEarlyAndLateFragmentTestsAMD = 5017,
     ExecutionModeStencilRefReplacingEXT = 5027,
+    ExecutionModeStencilRefUnchangedFrontAMD = 5079,
+    ExecutionModeStencilRefGreaterFrontAMD = 5080,
+    ExecutionModeStencilRefLessFrontAMD = 5081,
+    ExecutionModeStencilRefUnchangedBackAMD = 5082,
+    ExecutionModeStencilRefGreaterBackAMD = 5083,
+    ExecutionModeStencilRefLessBackAMD = 5084,
     ExecutionModeOutputLinesNV = 5269,
     ExecutionModeOutputPrimitivesNV = 5270,
     ExecutionModeDerivativeGroupQuadsNV = 5289,

+ 41 - 0
Test/baseResults/spv.earlyAndlateFragmentTests.frag.out

@@ -0,0 +1,41 @@
+spv.earlyAndlateFragmentTests.frag
+// Module Version 10000
+// Generated by (magic number): 8000a
+// Id's are bound by 16
+
+                              Capability Shader
+                              Extension  "SPV_AMD_shader_early_and_late_fragment_tests"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 8 11
+                              ExecutionMode 4 OriginUpperLeft
+                              ExecutionMode 4 EarlyAndLateFragmentTestsAMD
+                              ExecutionMode 4 DepthReplacing
+                              ExecutionMode 4 DepthLess
+                              Source GLSL 450
+                              SourceExtension  "GL_ARB_fragment_shader_interlock"
+                              SourceExtension  "GL_ARB_shader_stencil_export"
+                              SourceExtension  "GL_EXT_fragment_shading_rate"
+                              Name 4  "main"
+                              Name 8  "gl_FragDepth"
+                              Name 11  "instanceIndex"
+                              Decorate 8(gl_FragDepth) BuiltIn FragDepth
+                              Decorate 11(instanceIndex) Flat
+                              Decorate 11(instanceIndex) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypePointer Output 6(float)
+ 8(gl_FragDepth):      7(ptr) Variable Output
+               9:             TypeInt 32 1
+              10:             TypePointer Input 9(int)
+11(instanceIndex):     10(ptr) Variable Input
+              14:    6(float) Constant 1117913088
+         4(main):           2 Function None 3
+               5:             Label
+              12:      9(int) Load 11(instanceIndex)
+              13:    6(float) ConvertSToF 12
+              15:    6(float) FDiv 13 14
+                              Store 8(gl_FragDepth) 15
+                              Return
+                              FunctionEnd

+ 1 - 0
Test/baseResults/spv.shaderStencilExport.frag.out

@@ -10,6 +10,7 @@ spv.shaderStencilExport.frag
                               MemoryModel Logical GLSL450
                               EntryPoint Fragment 4  "main" 8
                               ExecutionMode 4 OriginUpperLeft
+                              ExecutionMode 4 StencilRefReplacingEXT
                               Source GLSL 450
                               SourceExtension  "GL_ARB_shader_stencil_export"
                               Name 4  "main"

+ 12 - 0
Test/spv.earlyAndlateFragmentTests.frag

@@ -0,0 +1,12 @@
+#version 450 core
+#extension GL_EXT_fragment_shading_rate : enable
+#extension GL_ARB_shader_stencil_export : enable
+#extension GL_ARB_fragment_shader_interlock : enable
+#extension GL_AMD_shader_early_and_late_fragment_tests : enable
+layout(location = 0) flat in int instanceIndex;
+layout(early_and_late_fragment_tests_amd) in;
+layout(depth_less) out float gl_FragDepth;
+void main()
+{
+  gl_FragDepth = float(instanceIndex) / float(81);
+}

+ 2 - 0
glslang/Include/BaseTypes.h

@@ -128,6 +128,7 @@ enum TStorageQualifier {
     // built-ins written by fragment shader
     EvqFragColor,
     EvqFragDepth,
+    EvqFragStencil,
 
     // end of list
     EvqLast
@@ -353,6 +354,7 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q)
     case EvqPointCoord:     return "gl_PointCoord";  break;
     case EvqFragColor:      return "fragColor";      break;
     case EvqFragDepth:      return "gl_FragDepth";   break;
+    case EvqFragStencil:    return "gl_FragStencilRefARB"; break;
     case EvqPayload:        return "rayPayloadNV";     break;
     case EvqPayloadIn:      return "rayPayloadInNV";   break;
     case EvqHitAttr:        return "hitAttributeNV";   break;

+ 35 - 0
glslang/Include/Types.h

@@ -443,6 +443,18 @@ enum TLayoutDepth {
     EldCount
 };
 
+enum TLayoutStencil {
+    ElsNone,
+    ElsRefUnchangedFrontAMD,
+    ElsRefGreaterFrontAMD,
+    ElsRefLessFrontAMD,
+    ElsRefUnchangedBackAMD,
+    ElsRefGreaterBackAMD,
+    ElsRefLessBackAMD,
+
+    ElsCount
+};
+
 enum TBlendEquationShift {
     // No 'EBlendNone':
     // These are used as bit-shift amounts.  A mask of such shifts will have type 'int',
@@ -705,6 +717,7 @@ public:
         case EvqVaryingOut:
         case EvqFragColor:
         case EvqFragDepth:
+        case EvqFragStencil:
             return true;
         default:
             return false;
@@ -772,6 +785,7 @@ public:
         case EvqVaryingOut:
         case EvqFragColor:
         case EvqFragDepth:
+        case EvqFragStencil:
             return true;
         default:
             return false;
@@ -1239,6 +1253,18 @@ public:
         default:           return "none";
         }
     }
+    static const char* getLayoutStencilString(TLayoutStencil s)
+    {
+        switch (s) {
+        case ElsRefUnchangedFrontAMD: return "stencil_ref_unchanged_front_amd";
+        case ElsRefGreaterFrontAMD:   return "stencil_ref_greater_front_amd";
+        case ElsRefLessFrontAMD:      return "stencil_ref_less_front_amd";
+        case ElsRefUnchangedBackAMD:  return "stencil_ref_unchanged_back_amd";
+        case ElsRefGreaterBackAMD:    return "stencil_ref_greater_back_amd";
+        case ElsRefLessBackAMD:       return "stencil_ref_less_back_amd";
+        default:                      return "none";
+        }
+    }
     static const char* getBlendEquationString(TBlendEquationShift e)
     {
         switch (e) {
@@ -1336,7 +1362,9 @@ struct TShaderQualifiers {
 #ifndef GLSLANG_WEB
     bool earlyFragmentTests;  // fragment input
     bool postDepthCoverage;   // fragment input
+    bool earlyAndLateFragmentTestsAMD; //fragment input
     TLayoutDepth layoutDepth;
+    TLayoutStencil layoutStencil;
     bool blendEquation;       // true if any blend equation was specified
     int numViews;             // multiview extenstions
     TInterlockOrdering interlockOrdering;
@@ -1346,6 +1374,7 @@ struct TShaderQualifiers {
     int primitives;                     // mesh shader "max_primitives"DerivativeGroupLinear;   // true if layout derivative_group_linearNV set
     bool layoutPrimitiveCulling;        // true if layout primitive_culling set
     TLayoutDepth getDepth() const { return layoutDepth; }
+    TLayoutStencil getStencil() const { return layoutStencil; }
 #else
     TLayoutDepth getDepth() const { return EldNone; }
 #endif
@@ -1371,8 +1400,10 @@ struct TShaderQualifiers {
         localSizeSpecId[2] = TQualifier::layoutNotSet;
 #ifndef GLSLANG_WEB
         earlyFragmentTests = false;
+        earlyAndLateFragmentTestsAMD = false;
         postDepthCoverage = false;
         layoutDepth = EldNone;
+        layoutStencil = ElsNone;
         blendEquation = false;
         numViews = TQualifier::layoutNotSet;
         layoutOverrideCoverage      = false;
@@ -1424,10 +1455,14 @@ struct TShaderQualifiers {
 #ifndef GLSLANG_WEB
         if (src.earlyFragmentTests)
             earlyFragmentTests = true;
+        if (src.earlyAndLateFragmentTestsAMD)
+            earlyAndLateFragmentTestsAMD = true;
         if (src.postDepthCoverage)
             postDepthCoverage = true;
         if (src.layoutDepth)
             layoutDepth = src.layoutDepth;
+        if (src.layoutStencil)
+            layoutStencil = src.layoutStencil;
         if (src.blendEquation)
             blendEquation = src.blendEquation;
         if (src.numViews != TQualifier::layoutNotSet)

+ 1 - 0
glslang/MachineIndependent/Initialize.cpp

@@ -8065,6 +8065,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         SpecialQualifier("gl_FragDepth",        EvqFragDepth,  EbvFragDepth,        symbolTable);
 #ifndef GLSLANG_WEB
         SpecialQualifier("gl_FragDepthEXT",     EvqFragDepth,  EbvFragDepth,        symbolTable);
+        SpecialQualifier("gl_FragStencilRefARB", EvqFragStencil, EbvFragStencilRef, symbolTable);
         SpecialQualifier("gl_HelperInvocation", EvqVaryingIn,  EbvHelperInvocation, symbolTable);
 
         BuiltInVariable("gl_ClipDistance",    EbvClipDistance,   symbolTable);

+ 42 - 2
glslang/MachineIndependent/ParseHelper.cpp

@@ -2988,6 +2988,12 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
         if (isEsProfile() && intermediate.getEarlyFragmentTests())
             message = "can't modify gl_FragDepth if using early_fragment_tests";
         break;
+    case EvqFragStencil:
+        intermediate.setStencilReplacing();
+        // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
+        if (isEsProfile() && intermediate.getEarlyFragmentTests())
+            message = "can't modify EvqFragStencil if using early_fragment_tests";
+        break;
 
     default:
         break;
@@ -4709,10 +4715,22 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
                 if (! intermediate.setDepth(publicType.layoutDepth))
                     error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str());
             }
+        } else if (identifier == "gl_FragStencilRefARB") {
+            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
+                qualifier.isMemory() || qualifier.isAuxiliary())
+                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());
+            if (publicType.layoutStencil != ElsNone) {
+                if (intermediate.inIoAccessed("gl_FragStencilRefARB"))
+                    error(loc, "cannot redeclare after use", "gl_FragStencilRefARB", "");
+                if (!intermediate.setStencil(publicType.layoutStencil))
+                    error(loc, "all redeclarations must use the same stencil layout on", "redeclaration",
+                          symbol->getName().c_str());
+            }
         }
         else if (
-            identifier == "gl_PrimitiveIndicesNV" ||
-            identifier == "gl_FragStencilRefARB") {
+            identifier == "gl_PrimitiveIndicesNV") {
             if (qualifier.hasLayout())
                 error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
             if (qualifier.storage != EvqVaryingOut)
@@ -5546,6 +5564,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
             publicType.shaderQualifiers.earlyFragmentTests = true;
             return;
         }
+        if (id == "early_and_late_fragment_tests_amd") {
+            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_AMD_shader_early_and_late_fragment_tests, "early_and_late_fragment_tests_amd");
+            profileRequires(loc, EEsProfile, 310, nullptr, "early_and_late_fragment_tests_amd");
+            publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD = true;
+            return;
+        }
         if (id == "post_depth_coverage") {
             requireExtensions(loc, Num_post_depth_coverageEXTs, post_depth_coverageEXTs, "post depth coverage");
             if (extensionTurnedOn(E_GL_ARB_post_depth_coverage)) {
@@ -5562,6 +5586,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
                 return;
             }
         }
+        for (TLayoutStencil stencil = (TLayoutStencil)(ElsNone + 1); stencil < ElsCount; stencil = (TLayoutStencil)(stencil+1)) {
+            if (id == TQualifier::getLayoutStencilString(stencil)) {
+                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "stencil layout qualifier");
+                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, nullptr, "stencil layout qualifier");
+                publicType.shaderQualifiers.layoutStencil = stencil;
+                return;
+            }
+        }
         for (TInterlockOrdering order = (TInterlockOrdering)(EioNone + 1); order < EioCount; order = (TInterlockOrdering)(order+1)) {
             if (id == TQualifier::getInterlockOrderingString(order)) {
                 requireProfile(loc, ECoreProfile | ECompatibilityProfile, "fragment shader interlock layout qualifier");
@@ -7259,6 +7291,8 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
         error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
     if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone)
         error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
+    if (identifier != "gl_FragStencilRefARB" && publicType.shaderQualifiers.getStencil() != ElsNone)
+        error(loc, "can only apply depth layout to gl_FragStencilRefARB", "layout qualifier", "");
 
     // Check for redeclaration of built-ins and/or attempting to declare a reserved name
     TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers);
@@ -9091,6 +9125,12 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
         else
             error(loc, "can only apply to 'in'", "early_fragment_tests", "");
     }
+    if (publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD) {
+        if (publicType.qualifier.storage == EvqVaryingIn)
+            intermediate.setEarlyAndLateFragmentTestsAMD();
+        else
+            error(loc, "can only apply to 'in'", "early_and_late_fragment_tests_amd", "");
+    }
     if (publicType.shaderQualifiers.postDepthCoverage) {
         if (publicType.qualifier.storage == EvqVaryingIn)
             intermediate.setPostDepthCoverage();

+ 1 - 0
glslang/MachineIndependent/Versions.cpp

@@ -275,6 +275,7 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_AMD_shader_image_load_store_lod]          = EBhDisable;
     extensionBehavior[E_GL_AMD_shader_fragment_mask]                 = EBhDisable;
     extensionBehavior[E_GL_AMD_gpu_shader_half_float_fetch]          = EBhDisable;
+    extensionBehavior[E_GL_AMD_shader_early_and_late_fragment_tests] = EBhDisable;
 
     extensionBehavior[E_GL_INTEL_shader_integer_functions2]          = EBhDisable;
 

+ 1 - 0
glslang/MachineIndependent/Versions.h

@@ -238,6 +238,7 @@ const char* const E_GL_AMD_gpu_shader_int16                     = "GL_AMD_gpu_sh
 const char* const E_GL_AMD_shader_image_load_store_lod          = "GL_AMD_shader_image_load_store_lod";
 const char* const E_GL_AMD_shader_fragment_mask                 = "GL_AMD_shader_fragment_mask";
 const char* const E_GL_AMD_gpu_shader_half_float_fetch          = "GL_AMD_gpu_shader_half_float_fetch";
+const char* const E_GL_AMD_shader_early_and_late_fragment_tests = "GL_AMD_shader_early_and_late_fragment_tests";
 
 const char* const E_GL_INTEL_shader_integer_functions2          = "GL_INTEL_shader_integer_functions2";
 

+ 17 - 1
glslang/MachineIndependent/localintermediate.h

@@ -296,6 +296,7 @@ public:
         invariantAll(false),
         nanMinMaxClamp(false),
         depthReplacing(false),
+        stencilReplacing(false),
         uniqueId(0),
         globalUniformBlockName(""),
         atomicCounterBlockName(""),
@@ -311,7 +312,7 @@ public:
         inputPrimitive(ElgNone), outputPrimitive(ElgNone),
         pixelCenterInteger(false), originUpperLeft(false),texCoordBuiltinRedeclared(false),
         vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false),
-        postDepthCoverage(false), depthLayout(EldNone),
+        postDepthCoverage(false), earlyAndLateFragmentTestsAMD(false), depthLayout(EldNone), stencilLayout(ElsNone),
         hlslFunctionality1(false),
         blendEquations(0), xfbMode(false), multiStream(false),
         layoutOverrideCoverage(false),
@@ -587,6 +588,8 @@ public:
     bool isInvariantAll() const { return invariantAll; }
     void setDepthReplacing() { depthReplacing = true; }
     bool isDepthReplacing() const { return depthReplacing; }
+    void setStencilReplacing() { stencilReplacing = true; }
+    bool isStencilReplacing() const { return stencilReplacing; }
     bool setLocalSize(int dim, int size)
     {
         if (localSizeNotDefault[dim])
@@ -821,7 +824,9 @@ public:
     void setPostDepthCoverage() { postDepthCoverage = true; }
     bool getPostDepthCoverage() const { return postDepthCoverage; }
     void setEarlyFragmentTests() { earlyFragmentTests = true; }
+    void setEarlyAndLateFragmentTestsAMD() { earlyAndLateFragmentTestsAMD = true; }
     bool getEarlyFragmentTests() const { return earlyFragmentTests; }
+    bool getEarlyAndLateFragmentTestsAMD() const { return earlyAndLateFragmentTestsAMD; }
     bool setDepth(TLayoutDepth d)
     {
         if (depthLayout != EldNone)
@@ -829,7 +834,15 @@ public:
         depthLayout = d;
         return true;
     }
+    bool setStencil(TLayoutStencil s)
+    {
+        if (stencilLayout != ElsNone)
+            return stencilLayout == s;
+        stencilLayout = s;
+        return true;
+    }
     TLayoutDepth getDepth() const { return depthLayout; }
+    TLayoutStencil getStencil() const { return stencilLayout; }
     void setOriginUpperLeft() { originUpperLeft = true; }
     bool getOriginUpperLeft() const { return originUpperLeft; }
     void setPixelCenterInteger() { pixelCenterInteger = true; }
@@ -1100,6 +1113,7 @@ protected:
     bool invariantAll;
     bool nanMinMaxClamp;            // true if desiring min/max/clamp to favor non-NaN over NaN
     bool depthReplacing;
+    bool stencilReplacing;
     int localSize[3];
     bool localSizeNotDefault[3];
     int localSizeSpecId[3];
@@ -1131,7 +1145,9 @@ protected:
     bool pointMode;
     bool earlyFragmentTests;
     bool postDepthCoverage;
+    bool earlyAndLateFragmentTestsAMD;
     TLayoutDepth depthLayout;
+    TLayoutStencil stencilLayout;
     bool hlslFunctionality1;
     int blendEquations;        // an 'or'ing of masks of shifts of TBlendEquationShift
     bool xfbMode;