From 0ad6a4e60d91704a0b51d4b3d28bb279f609ba78 Mon Sep 17 00:00:00 2001
From: chaoc <chaoc@nvidia.com>
Date: Mon, 19 Dec 2016 16:29:34 -0800
Subject: [PATCH] Add support for SPV_NV_sample_mask_override_coverage

---
 CMakeLists.txt                                |  6 +++
 SPIRV/CMakeLists.txt                          |  5 +++
 SPIRV/GLSL.ext.NV.h                           | 42 +++++++++++++++++++
 SPIRV/GlslangToSpv.cpp                        | 19 +++++++++
 SPIRV/disassemble.cpp                         | 33 +++++++++++++++
 SPIRV/doc.cpp                                 |  6 +++
 .../spv.sampleMaskOverrideCoverage.frag.out   | 42 +++++++++++++++++++
 Test/spv.sampleMaskOverrideCoverage.frag      |  7 ++++
 glslang/Include/Types.h                       | 12 ++++++
 glslang/MachineIndependent/ParseHelper.cpp    | 20 ++++++++-
 glslang/MachineIndependent/Versions.cpp       |  8 ++++
 glslang/MachineIndependent/Versions.h         |  3 ++
 .../MachineIndependent/localintermediate.h    | 12 ++++++
 gtests/Spv.FromFile.cpp                       |  1 +
 14 files changed, 215 insertions(+), 1 deletion(-)
 create mode 100644 SPIRV/GLSL.ext.NV.h
 create mode 100644 Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out
 create mode 100644 Test/spv.sampleMaskOverrideCoverage.frag

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33b4764d5..aaefe1237 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 option(ENABLE_AMD_EXTENSIONS "Enables support of AMD-specific extensions" ON)
 
+option(ENABLE_NV_EXTENSIONS "Enables support of Nvidia-specific extensions" ON)
+
 enable_testing()
 
 set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "prefix")
@@ -13,6 +15,10 @@ if(ENABLE_AMD_EXTENSIONS)
     add_definitions(-DAMD_EXTENSIONS)
 endif(ENABLE_AMD_EXTENSIONS)
 
+if(ENABLE_NV_EXTENSIONS)
+    add_definitions(-DNV_EXTENSIONS)
+endif(ENABLE_NV_EXTENSIONS)
+
 if(WIN32)
     set(CMAKE_DEBUG_POSTFIX "d")
     include(ChooseMSVCCRT.cmake)
diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt
index 2c65d71a6..c538e8415 100755
--- a/SPIRV/CMakeLists.txt
+++ b/SPIRV/CMakeLists.txt
@@ -33,6 +33,11 @@ if(ENABLE_AMD_EXTENSIONS)
          GLSL.ext.AMD.h)
 endif(ENABLE_AMD_EXTENSIONS)
 
+if(ENABLE_NV_EXTENSIONS)
+    set(HEADERS
+        GLSL.ext.NV.h)
+endif(ENABLE_NV_EXTENSIONS)
+
 add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
 set_property(TARGET SPIRV PROPERTY FOLDER glslang)
 
diff --git a/SPIRV/GLSL.ext.NV.h b/SPIRV/GLSL.ext.NV.h
new file mode 100644
index 000000000..8e9298ca8
--- /dev/null
+++ b/SPIRV/GLSL.ext.NV.h
@@ -0,0 +1,42 @@
+/*
+** Copyright (c) 2014-2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and/or associated documentation files (the "Materials"),
+** to deal in the Materials without restriction, including without limitation
+** the rights to use, copy, modify, merge, publish, distribute, sublicense,
+** and/or sell copies of the Materials, and to permit persons to whom the
+** Materials are furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Materials.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+** IN THE MATERIALS.
+*/
+
+#ifndef GLSLextNV_H
+#define GLSLextNV_H
+
+enum BuiltIn;
+enum Decoration;
+enum Op;
+
+static const int GLSLextNVVersion = 100;
+static const int GLSLextNVRevision = 1;
+
+//SPV_NV_sample_mask_override_coverage
+const char* const E_SPV_NV_sample_mask_override_coverage = "SPV_NV_sample_mask_override_coverage";
+
+static const Decoration OverrideCoverageNV = static_cast<Decoration>(5248);
+
+#endif  // #ifndef GLSLextNV_H
\ No newline at end of file
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 15af947c2..71af11bc5 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -47,6 +47,9 @@ namespace spv {
 #ifdef AMD_EXTENSIONS
     #include "GLSL.ext.AMD.h"
 #endif
+#ifdef NV_EXTENSIONS
+    #include "GLSL.ext.NV.h"
+#endif
 }
 
 // Glslang includes
@@ -436,6 +439,7 @@ spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qual
         return spv::DecorationMax;
 }
 
+
 // Translate a glslang built-in variable to a SPIR-V built in decoration.  Also generate
 // associated capabilities when required.  For some built-in variables, a capability
 // is generated only when using the variable in an executable instruction, but not when
@@ -4721,6 +4725,21 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
     if (builtIn != spv::BuiltInMax)
         addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
 
+#ifdef NV_EXTENSIONS 
+    if (builtIn == spv::BuiltInSampleMask) {
+          spv::Decoration decoration;
+          // GL_NV_sample_mask_override_coverage extension
+          if (glslangIntermediate->getLayoutOverrideCoverage())
+              decoration = (spv::Decoration)spv::OverrideCoverageNV;
+          else
+              decoration = (spv::Decoration)spv::DecorationMax;
+        addDecoration(id, decoration);
+        if (decoration != spv::DecorationMax) {
+            builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
+        }
+    }
+#endif
+
     return id;
 }
 
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index b1023b921..092711884 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -53,6 +53,9 @@ namespace spv {
         #include "GLSL.std.450.h"
 #ifdef AMD_EXTENSIONS
         #include "GLSL.ext.AMD.h"
+#endif
+#ifdef NV_EXTENSIONS
+        #include "GLSL.ext.NV.h"
 #endif
     }
 }
@@ -64,6 +67,10 @@ namespace spv {
 static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
 #endif
 
+#ifdef NV_EXTENSIONS
+static const char* GLSLextNVGetDebugNames(const char*, unsigned);
+#endif
+
 static void Kill(std::ostream& out, const char* message)
 {
     out << std::endl << "Disassembly failed: " << message << std::endl;
@@ -75,6 +82,9 @@ enum ExtInstSet {
     GLSL450Inst,
 #ifdef AMD_EXTENSIONS
     GLSLextAMDInst,
+#endif
+#ifdef NV_EXTENSIONS
+    GLSLextNVInst,
 #endif
     OpenCLExtInst,
 };
@@ -469,6 +479,10 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
                            strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
                            strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
                     extInstSet = GLSLextAMDInst;
+#endif
+#ifdef NV_EXTENSIONS
+                } else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0) {
+                    extInstSet = GLSLextNVInst;
 #endif
                 }
                 unsigned entrypoint = stream[word - 1];
@@ -479,6 +493,11 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
 #ifdef AMD_EXTENSIONS
                 } else if (extInstSet == GLSLextAMDInst) {
                     out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
+#endif
+#ifdef NV_EXTENSIONS
+                }
+                else if (extInstSet == GLSLextNVInst) {
+                    out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
 #endif
                 }
             }
@@ -631,6 +650,20 @@ static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint
 }
 #endif
 
+
+#ifdef NV_EXTENSIONS
+static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
+{
+    if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0) {
+        switch (entrypoint) {
+        case OverrideCoverageNV:    return "OverrideCoverageNV";
+        default:                    return "Bad";
+        }
+    }
+    return "Bad";
+}
+#endif
+
 void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
 {
     SpirvStream SpirvStream(out, stream);
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 0e68c7ef0..878dcf594 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -50,6 +50,9 @@ namespace spv {
         // Include C-based headers that don't have a namespace
 #ifdef AMD_EXTENSIONS
         #include "GLSL.ext.AMD.h"
+#endif
+#ifdef NV_EXTENSIONS
+        #include "GLSL.ext.NV.h"
 #endif
     }
 }
@@ -255,6 +258,9 @@ const char* DecorationString(int decoration)
 
 #ifdef AMD_EXTENSIONS
     case 4999: return "ExplicitInterpAMD";
+#endif
+#ifdef NV_EXTENSIONS
+    case 5248: return "OverrideCoverageNV";
 #endif
     }
 }
diff --git a/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out b/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out
new file mode 100644
index 000000000..6bae6bd0c
--- /dev/null
+++ b/Test/baseResults/spv.sampleMaskOverrideCoverage.frag.out
@@ -0,0 +1,42 @@
+spv.sampleMaskOverrideCoverage.frag
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 20
+
+                              Capability Shader
+                              Capability SampleRateShading
+                              Extension  "SPV_NV_sample_mask_override_coverage"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 11 19
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_NV_sample_mask_override_coverage"
+                              Name 4  "main"
+                              Name 11  "gl_SampleMask"
+                              Name 19  "color"
+                              Decorate 11(gl_SampleMask) BuiltIn SampleMask
+                              Decorate 11(gl_SampleMask) OverrideCoverageNV
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeInt 32 1
+               7:             TypeInt 32 0
+               8:      7(int) Constant 1
+               9:             TypeArray 6(int) 8
+              10:             TypePointer Output 9
+11(gl_SampleMask):     10(ptr) Variable Output
+              12:      6(int) Constant 0
+              13:      6(int) Constant 4294967295
+              14:             TypePointer Output 6(int)
+              16:             TypeFloat 32
+              17:             TypeVector 16(float) 4
+              18:             TypePointer Input 17(fvec4)
+       19(color):     18(ptr) Variable Input
+         4(main):           2 Function None 3
+               5:             Label
+              15:     14(ptr) AccessChain 11(gl_SampleMask) 12
+                              Store 15 13
+                              Return
+                              FunctionEnd
diff --git a/Test/spv.sampleMaskOverrideCoverage.frag b/Test/spv.sampleMaskOverrideCoverage.frag
new file mode 100644
index 000000000..dd8406218
--- /dev/null
+++ b/Test/spv.sampleMaskOverrideCoverage.frag
@@ -0,0 +1,7 @@
+#version 450
+#extension GL_NV_sample_mask_override_coverage : enable
+in vec4 color;
+layout(override_coverage) out int gl_SampleMask[];
+void main() {
+    gl_SampleMask[0] = int(0xFFFFFFFF);
+}
\ No newline at end of file
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 8745c7a94..fc562c328 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -920,6 +920,10 @@ struct TShaderQualifiers {
     TLayoutDepth layoutDepth;
     bool blendEquation;       // true if any blend equation was specified
 
+#ifdef NV_EXTENSIONS 
+    bool layoutOverrideCoverage;    // true if layout override_coverage set
+#endif 
+
     void init()
     {
         geometry = ElgNone;
@@ -939,6 +943,9 @@ struct TShaderQualifiers {
         earlyFragmentTests = false;
         layoutDepth = EldNone;
         blendEquation = false;
+#ifdef NV_EXTENSIONS 
+        layoutOverrideCoverage = false;
+#endif
     }
 
     // Merge in characteristics from the 'src' qualifier.  They can override when
@@ -975,6 +982,10 @@ struct TShaderQualifiers {
             layoutDepth = src.layoutDepth;
         if (src.blendEquation)
             blendEquation = src.blendEquation;
+#ifdef NV_EXTENSIONS 
+        if (src.layoutOverrideCoverage)
+            layoutOverrideCoverage = src.layoutOverrideCoverage;
+#endif 
     }
 };
 
@@ -1525,6 +1536,7 @@ public:
                     p += snprintf(p, end - p, "constant_id=%d ", qualifier.layoutSpecConstantId);
                 if (qualifier.layoutPushConstant)
                     p += snprintf(p, end - p, "push_constant ");
+
                 p += snprintf(p, end - p, ") ");
             }
         }
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index ed043e0a0..7a8cbfe2c 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -3304,6 +3304,9 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
          identifier == "gl_BackSecondaryColor"                                                      ||
          identifier == "gl_SecondaryColor"                                                          ||
         (identifier == "gl_Color"               && language == EShLangFragment)                     ||
+#ifdef NV_EXTENSIONS
+         identifier == "gl_SampleMask"                                                              ||
+#endif
          identifier == "gl_TexCoord") {
 
         // Find the existing symbol, if any.
@@ -3381,8 +3384,16 @@ 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());
             }
-
         }
+#ifdef NV_EXTENSIONS 
+        else if (identifier == "gl_SampleMask") {
+            if (!publicType.layoutOverrideCoverage) {
+                error(loc, "redeclaration only allowed for override_coverage layout", "redeclaration", symbol->getName().c_str());
+            }
+            intermediate.setLayoutOverrideCoverage();
+        }
+#endif
+
         // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
 
         return symbol;
@@ -4005,6 +4016,13 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
                 error(loc, "unknown blend equation", "blend_support", "");
             return;
         }
+#ifdef NV_EXTENSIONS 
+        if (id == "override_coverage") {
+            requireExtensions(loc, 1, &E_GL_NV_sample_mask_override_coverage, "sample mask override coverage");
+            publicType.shaderQualifiers.layoutOverrideCoverage = true;
+            return;
+        }
+#endif
     }
     error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
 }
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 8a29cb37f..5f3fdb230 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -195,6 +195,10 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_AMD_gpu_shader_half_float]                = EBhDisable;
 #endif
 
+#ifdef NV_EXTENSIONS 
+    extensionBehavior[E_GL_NV_sample_mask_override_coverage]         = EBhDisable;
+#endif
+
     // AEP
     extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
     extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
@@ -302,6 +306,10 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_AMD_gcn_shader 1\n"
             "#define GL_AMD_gpu_shader_half_float 1\n"
 #endif
+
+#ifdef NV_EXTENSIONS 
+            "#define GL_NV_sample_mask_override_coverage 1\n"
+#endif
             ;
     }
 
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index 17baf3b1a..433cee573 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -142,6 +142,9 @@ const char* const E_GL_AMD_shader_explicit_vertex_parameter     = "GL_AMD_shader
 const char* const E_GL_AMD_gcn_shader                           = "GL_AMD_gcn_shader";
 const char* const E_GL_AMD_gpu_shader_half_float                = "GL_AMD_gpu_shader_half_float";
 #endif
+#ifdef NV_EXTENSIONS
+const char* const E_GL_NV_sample_mask_override_coverage = "GL_NV_sample_mask_override_coverage";
+#endif
 
 // AEP
 const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 6f6db92d5..8921456fc 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -151,6 +151,9 @@ public:
         shiftUboBinding(0),
         autoMapBindings(false),
         flattenUniformArrays(false),
+#ifdef NV_EXTENSIONS 
+        layoutOverrideCoverage(false),
+#endif
         useUnknownFormat(false)
     {
         localSize[0] = 1;
@@ -387,6 +390,11 @@ public:
     static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
     bool promote(TIntermOperator*);
 
+#ifdef NV_EXTENSIONS 
+    void setLayoutOverrideCoverage() { layoutOverrideCoverage = true; }
+    bool getLayoutOverrideCoverage() const { return layoutOverrideCoverage; }
+#endif
+
 protected:
     TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
     void error(TInfoSink& infoSink, const char*);
@@ -447,6 +455,10 @@ protected:
     bool xfbMode;
     bool multiStream;
 
+#ifdef NV_EXTENSIONS 
+    bool layoutOverrideCoverage;
+#endif
+
     typedef std::list<TCall> TGraph;
     TGraph callGraph;
 
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 414fa7b7d..8593c62d3 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -240,6 +240,7 @@ INSTANTIATE_TEST_CASE_P(
         "spv.precision.frag",
         "spv.prepost.frag",
         "spv.qualifiers.vert",
+        "spv.sampleMaskOverrideCoverage.frag",
         "spv.shaderBallot.comp",
         "spv.shaderDrawParams.vert",
         "spv.shaderGroupVote.comp",
-- 
GitLab