support SPV_NV_viewport_array2 and SPV_NV_stereo_view_rendering
diff --git a/SPIRV/GLSL.ext.NV.h b/SPIRV/GLSL.ext.NV.h
index adfcb0f..89f0a5c 100644
--- a/SPIRV/GLSL.ext.NV.h
+++ b/SPIRV/GLSL.ext.NV.h
@@ -30,20 +30,45 @@
 enum BuiltIn;
 enum Decoration;
 enum Op;
+enum Capability;
 
 static const int GLSLextNVVersion = 100;
-static const int GLSLextNVRevision = 2;
+static const int GLSLextNVRevision = 4;
 
 //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);
+static const Decoration DecorationOverrideCoverageNV = static_cast<Decoration>(5248);
 
 
 //SPV_NV_geometry_shader_passthrough
 const char* const E_SPV_NV_geometry_shader_passthrough = "SPV_NV_geometry_shader_passthrough";
 
-static const Decoration PassthroughNV = static_cast<Decoration>(5250);
+static const Decoration DecorationPassthroughNV = static_cast<Decoration>(5250);
 
-static const Capability GeometryShaderPassthroughNV = static_cast<Capability>(5251);
+static const Capability CapabilityGeometryShaderPassthroughNV = static_cast<Capability>(5251);
+
+
+//SPV_NV_viewport_array2
+const char* const E_SPV_NV_viewport_array2 = "SPV_NV_viewport_array2";
+const char* const E_ARB_shader_viewport_layer_array = "SPV_ARB_shader_viewport_layer_array";
+
+static const Decoration DecorationViewportRelativeNV = static_cast<Decoration>(5252);
+
+static const BuiltIn BuiltInViewportMaskNV = static_cast<BuiltIn>(5253);
+
+static const Capability CapabilityShaderViewportIndexLayerNV = static_cast<Capability>(5254);
+static const Capability CapabilityShaderViewportMaskNV       = static_cast<Capability>(5255);
+
+
+//SPV_NV_stereo_view_rendering
+const char* const E_SPV_NV_stereo_view_rendering = "SPV_NV_stereo_view_rendering";
+
+static const Decoration DecorationSecondaryViewportRelativeNV = static_cast<Decoration>(5256);
+
+static const BuiltIn BuiltInSecondaryPositionNV = static_cast<BuiltIn>(5257);
+static const BuiltIn BuiltInSecondaryViewportMaskNV = static_cast<BuiltIn>(5258);
+
+static const Capability CapabilityShaderStereoViewNV = static_cast<Capability>(5259);
+
 #endif  // #ifndef GLSLextNV_H
\ No newline at end of file
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 81243f9..f83d82f 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -482,6 +482,15 @@
 
     case glslang::EbvViewportIndex:
         builder.addCapability(spv::CapabilityMultiViewport);
+#ifdef NV_EXTENSIONS
+        if (glslangIntermediate->getStage() == EShLangVertex ||
+            glslangIntermediate->getStage() == EShLangTessControl ||
+            glslangIntermediate->getStage() == EShLangTessEvaluation)
+        {
+            builder.addExtension(spv::E_SPV_NV_viewport_array2);
+            builder.addCapability(spv::CapabilityShaderViewportIndexLayerNV);
+        }
+#endif
         return spv::BuiltInViewportIndex;
 
     case glslang::EbvSampleId:
@@ -498,6 +507,18 @@
 
     case glslang::EbvLayer:
         builder.addCapability(spv::CapabilityGeometry);
+#ifdef NV_EXTENSIONS
+        if (!memberDeclaration)
+        {
+            if (glslangIntermediate->getStage() == EShLangVertex ||
+                glslangIntermediate->getStage() == EShLangTessControl ||
+                glslangIntermediate->getStage() == EShLangTessEvaluation)
+            {
+                builder.addExtension(spv::E_SPV_NV_viewport_array2);
+                builder.addCapability(spv::CapabilityShaderViewportIndexLayerNV);
+            }
+        }
+#endif
         return spv::BuiltInLayer;
 
     case glslang::EbvPosition:             return spv::BuiltInPosition;
@@ -607,6 +628,21 @@
         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
         return spv::BuiltInBaryCoordPullModelAMD;
 #endif
+
+#ifdef NV_EXTENSIONS
+    case glslang::EbvViewportMaskNV:
+        builder.addExtension(spv::E_SPV_NV_viewport_array2);
+        builder.addCapability(spv::CapabilityShaderViewportMaskNV);
+        return spv::BuiltInViewportMaskNV;
+    case glslang::EbvSecondaryPositionNV:
+        builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
+        builder.addCapability(spv::CapabilityShaderStereoViewNV);
+        return spv::BuiltInSecondaryPositionNV;
+    case glslang::EbvSecondaryViewportMaskNV:
+        builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
+        builder.addCapability(spv::CapabilityShaderStereoViewNV);
+        return spv::BuiltInSecondaryViewportMaskNV;
+#endif 
     default:                               return spv::BuiltInMax;
     }
 }
@@ -2275,6 +2311,22 @@
             spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
             if (builtIn != spv::BuiltInMax)
                 addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
+
+#ifdef NV_EXTENSIONS
+            if (builtIn == spv::BuiltInLayer) {
+                // SPV_NV_viewport_array2 extension
+                if (glslangMember.getQualifier().layoutViewportRelative){
+                    addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV);
+                    builder.addCapability(spv::CapabilityShaderViewportMaskNV);
+                    builder.addExtension(spv::E_SPV_NV_viewport_array2);
+                }
+                if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){
+                    addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV, glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);
+                    builder.addCapability(spv::CapabilityShaderStereoViewNV);
+                    builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
+                }
+            }
+#endif
         }
     }
 
@@ -2546,6 +2598,12 @@
     case glslang::EbvClipDistance:
     case glslang::EbvCullDistance:
     case glslang::EbvPointSize:
+#ifdef NV_EXTENSIONS
+    case glslang::EbvLayer:
+    case glslang::EbvViewportMaskNV:
+    case glslang::EbvSecondaryPositionNV:
+    case glslang::EbvSecondaryViewportMaskNV:
+#endif
         // Generate the associated capability.  Delegate to TranslateBuiltInDecoration.
         // Alternately, we could just call this for any glslang built-in, since the
         // capability already guards against duplicates.
@@ -4800,7 +4858,7 @@
           spv::Decoration decoration;
           // GL_NV_sample_mask_override_coverage extension
           if (glslangIntermediate->getLayoutOverrideCoverage())
-              decoration = (spv::Decoration)spv::OverrideCoverageNV;
+              decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV;
           else
               decoration = (spv::Decoration)spv::DecorationMax;
         addDecoration(id, decoration);
@@ -4808,9 +4866,25 @@
             builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
         }
     }
+    else if (builtIn == spv::BuiltInLayer) {
+        // SPV_NV_viewport_array2 extension
+        if (symbol->getQualifier().layoutViewportRelative)
+        {
+            addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV);
+            builder.addCapability(spv::CapabilityShaderViewportMaskNV);
+            builder.addExtension(spv::E_SPV_NV_viewport_array2);
+        }
+        if(symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048)
+        {
+            addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV, symbol->getQualifier().layoutSecondaryViewportRelativeOffset);
+            builder.addCapability(spv::CapabilityShaderStereoViewNV);
+            builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
+        }
+    }
+
     if (symbol->getQualifier().layoutPassthrough) {
-        addDecoration(id, spv::PassthroughNV);
-        builder.addCapability(spv::GeometryShaderPassthroughNV);
+        addDecoration(id, spv::DecorationPassthroughNV);
+        builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
         builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
     }
 #endif
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index a8049b8..74ae407 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -482,7 +482,8 @@
 #endif
 #ifdef NV_EXTENSIONS
                 }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
-                          strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0) {
+                          strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
+                          strcmp(spv::E_SPV_NV_viewport_array2, name) == 0) {
                     extInstSet = GLSLextNVInst;
 #endif
                 }
@@ -656,12 +657,21 @@
 static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
 {
     if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
-        strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0) {
+        strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
+        strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
+        strcmp(name, spv::E_SPV_NV_viewport_array2) == 0){
         switch (entrypoint) {
-        case OverrideCoverageNV:          return "OverrideCoverageNV";
-        case PassthroughNV:               return "PassthroughNV";
-        case GeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
-        default:                          return "Bad";
+        case DecorationOverrideCoverageNV:          return "OverrideCoverageNV";
+        case DecorationPassthroughNV:               return "PassthroughNV";
+        case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
+        case DecorationViewportRelativeNV:          return "ViewportRelativeNV";
+        case BuiltInViewportMaskNV:                 return "ViewportMaskNV";
+        case CapabilityShaderViewportMaskNV:        return "ShaderViewportMaskNV";
+        case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
+        case BuiltInSecondaryPositionNV:            return "SecondaryPositionNV";
+        case BuiltInSecondaryViewportMaskNV:        return "SecondaryViewportMaskNV";
+        case CapabilityShaderStereoViewNV:          return "ShaderStereoViewNV";
+        default:                                    return "Bad";
         }
     }
     return "Bad";
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 0bb9e01..8718099 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -262,6 +262,8 @@
 #ifdef NV_EXTENSIONS
     case 5248: return "OverrideCoverageNV";
     case 5250: return "PassthroughNV";
+    case 5252: return "ViewportRelativeNV";
+    case 5256: return "SecondaryViewportRelativeNV";
 #endif
     }
 }
@@ -338,6 +340,11 @@
     case 4997: return "BaryCoordSmoothSampleAMD";
     case 4998: return "BaryCoordPullModelAMD";
 #endif
+#ifdef NV_EXTENSIONS
+    case 5253: return "ViewportMaskNV";
+    case 5257: return "SecondaryPositionNV";
+    case 5258: return "SecondaryViewportMaskNV";
+#endif
     }
 }
 
@@ -823,6 +830,9 @@
 
 #ifdef NV_EXTENSIONS
     case 5251: return "GeometryShaderPassthroughNV";
+    case 5254: return "ShaderViewportIndexLayerNV";
+    case 5255: return "ShaderViewportMaskNV";
+    case 5259: return "ShaderStereoViewNV";
 #endif
 
     }