diff --git a/CMakeLists.txt b/CMakeLists.txt index 33b4764d..aaefe123 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 2c65d71a..c538e841 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 00000000..8e9298ca --- /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(5248); + +#endif // #ifndef GLSLextNV_H \ No newline at end of file diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 15af947c..71af11bc 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 b1023b92..09271188 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& stream) { SpirvStream SpirvStream(out, stream); diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp index 0e68c7ef..878dcf59 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 00000000..6bae6bd0 --- /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 00000000..dd840621 --- /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 8745c7a9..fc562c32 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 ed043e0a..7a8cbfe2 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 8a29cb37..5f3fdb23 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 17baf3b1..433cee57 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 6f6db92d..8921456f 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 TGraph; TGraph callGraph; diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index 414fa7b7..8593c62d 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",