diff --git a/SPIRV/GLSL.ext.KHR.h b/SPIRV/GLSL.ext.KHR.h index 333442bb..bcc6087d 100644 --- a/SPIRV/GLSL.ext.KHR.h +++ b/SPIRV/GLSL.ext.KHR.h @@ -41,5 +41,6 @@ static const char* const E_SPV_KHR_storage_buffer_storage_class = "SPV_KHR_stora static const char* const E_SPV_KHR_post_depth_coverage = "SPV_KHR_post_depth_coverage"; static const char* const E_SPV_KHR_vulkan_memory_model = "SPV_KHR_vulkan_memory_model"; static const char* const E_SPV_EXT_physical_storage_buffer = "SPV_EXT_physical_storage_buffer"; +static const char* const E_SPV_EXT_fragment_shader_interlock = "SPV_EXT_fragment_shader_interlock"; #endif // #ifndef GLSLextKHR_H diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index c513cd18..7eba1b6a 100644 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -1469,6 +1469,30 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); + + switch (glslangIntermediate->getInterlockOrdering()) { + case glslang::EioPixelInterlockOrdered: mode = spv::ExecutionModePixelInterlockOrderedEXT; break; + case glslang::EioPixelInterlockUnordered: mode = spv::ExecutionModePixelInterlockUnorderedEXT; break; + case glslang::EioSampleInterlockOrdered: mode = spv::ExecutionModeSampleInterlockOrderedEXT; break; + case glslang::EioSampleInterlockUnordered: mode = spv::ExecutionModeSampleInterlockUnorderedEXT; break; + case glslang::EioShadingRateInterlockOrdered: mode = spv::ExecutionModeShadingRateInterlockOrderedEXT; break; + case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionModeShadingRateInterlockUnorderedEXT; break; + default: mode = spv::ExecutionModeMax; break; + } + if (mode != spv::ExecutionModeMax) { + builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); + if (mode == spv::ExecutionModeShadingRateInterlockOrderedEXT || + mode == spv::ExecutionModeShadingRateInterlockUnorderedEXT) { + builder.addCapability(spv::CapabilityFragmentShaderShadingRateInterlockEXT); + } else if (mode == spv::ExecutionModePixelInterlockOrderedEXT || + mode == spv::ExecutionModePixelInterlockUnorderedEXT) { + builder.addCapability(spv::CapabilityFragmentShaderPixelInterlockEXT); + } else { + builder.addCapability(spv::CapabilityFragmentShaderSampleInterlockEXT); + } + builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); + } + break; case EShLangCompute: @@ -2396,6 +2420,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpCooperativeMatrixStore: noReturnValue = true; break; + case glslang::EOpBeginInvocationInterlock: + case glslang::EOpEndInvocationInterlock: + builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); + noReturnValue = true; + break; default: break; @@ -7429,6 +7458,14 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv: builder.createNoResultOp(spv::OpTerminateRayNV); return 0; #endif + + case glslang::EOpBeginInvocationInterlock: + builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT); + return 0; + case glslang::EOpEndInvocationInterlock: + builder.createNoResultOp(spv::OpEndInvocationInterlockEXT); + return 0; + default: logger->missingFunctionality("unknown operation with no arguments"); return 0; diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp index a0c384a1..da9494d4 100644 --- a/SPIRV/doc.cpp +++ b/SPIRV/doc.cpp @@ -191,6 +191,13 @@ const char* ExecutionModeString(int mode) case ExecutionModeDerivativeGroupLinearNV: return "DerivativeGroupLinearNV"; #endif + case ExecutionModePixelInterlockOrderedEXT: return "PixelInterlockOrderedEXT"; + case ExecutionModePixelInterlockUnorderedEXT: return "PixelInterlockUnorderedEXT"; + case ExecutionModeSampleInterlockOrderedEXT: return "SampleInterlockOrderedEXT"; + case ExecutionModeSampleInterlockUnorderedEXT: return "SampleInterlockUnorderedEXT"; + case ExecutionModeShadingRateInterlockOrderedEXT: return "ShadingRateInterlockOrderedEXT"; + case ExecutionModeShadingRateInterlockUnorderedEXT: return "ShadingRateInterlockUnorderedEXT"; + case ExecutionModeCeiling: default: return "Bad"; } @@ -942,6 +949,10 @@ const char* CapabilityString(int info) case CapabilityCooperativeMatrixNV: return "CooperativeMatrixNV"; + case CapabilityFragmentShaderSampleInterlockEXT: return "CapabilityFragmentShaderSampleInterlockEXT"; + case CapabilityFragmentShaderPixelInterlockEXT: return "CapabilityFragmentShaderPixelInterlockEXT"; + case CapabilityFragmentShaderShadingRateInterlockEXT: return "CapabilityFragmentShaderShadingRateInterlockEXT"; + default: return "Bad"; } } @@ -1352,6 +1363,9 @@ const char* OpcodeString(int op) case OpCooperativeMatrixMulAddNV: return "OpCooperativeMatrixMulAddNV"; case OpCooperativeMatrixLengthNV: return "OpCooperativeMatrixLengthNV"; + case OpBeginInvocationInterlockEXT: return "OpBeginInvocationInterlockEXT"; + case OpEndInvocationInterlockEXT: return "OpEndInvocationInterlockEXT"; + default: return "Bad"; } @@ -1465,6 +1479,8 @@ void Parameterize() InstructionDesc[OpModuleProcessed].setResultAndType(false, false); InstructionDesc[OpTypeCooperativeMatrixNV].setResultAndType(true, false); InstructionDesc[OpCooperativeMatrixStoreNV].setResultAndType(false, false); + InstructionDesc[OpBeginInvocationInterlockEXT].setResultAndType(false, false); + InstructionDesc[OpEndInvocationInterlockEXT].setResultAndType(false, false); // Specific additional context-dependent operands diff --git a/SPIRV/spirv.hpp b/SPIRV/spirv.hpp index 5297fd39..03ba767c 100644 --- a/SPIRV/spirv.hpp +++ b/SPIRV/spirv.hpp @@ -154,6 +154,12 @@ enum ExecutionMode { ExecutionModeDerivativeGroupQuadsNV = 5289, ExecutionModeDerivativeGroupLinearNV = 5290, ExecutionModeOutputTrianglesNV = 5298, + ExecutionModePixelInterlockOrderedEXT = 5366, + ExecutionModePixelInterlockUnorderedEXT = 5367, + ExecutionModeSampleInterlockOrderedEXT = 5368, + ExecutionModeSampleInterlockUnorderedEXT = 5369, + ExecutionModeShadingRateInterlockOrderedEXT = 5370, + ExecutionModeShadingRateInterlockUnorderedEXT = 5371, ExecutionModeMax = 0x7fffffff, }; @@ -551,6 +557,10 @@ enum BuiltIn { BuiltInHitTNV = 5332, BuiltInHitKindNV = 5333, BuiltInIncomingRayFlagsNV = 5351, + BuiltInWarpsPerSMNV = 5374, + BuiltInSMCountNV = 5375, + BuiltInWarpIDNV = 5376, + BuiltInSMIDNV = 5377, BuiltInMax = 0x7fffffff, }; @@ -829,10 +839,15 @@ enum Capability { CapabilityPhysicalStorageBufferAddressesEXT = 5347, CapabilityComputeDerivativeGroupLinearNV = 5350, CapabilityCooperativeMatrixNV = 5357, + CapabilityFragmentShaderSampleInterlockEXT = 5363, + CapabilityFragmentShaderShadingRateInterlockEXT = 5372, + CapabilityShaderSMBuiltinsNV = 5373, + CapabilityFragmentShaderPixelInterlockEXT = 5378, CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityIntegerFunctions2INTEL = 5584, CapabilitySubgroupAvcMotionEstimationINTEL = 5696, CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, @@ -1214,6 +1229,8 @@ enum Op { OpCooperativeMatrixStoreNV = 5360, OpCooperativeMatrixMulAddNV = 5361, OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1224,6 +1241,20 @@ enum Op { OpSubgroupImageBlockWriteINTEL = 5578, OpSubgroupImageMediaBlockReadINTEL = 5580, OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, OpMemberDecorateString = 5633, @@ -1738,10 +1769,22 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; case OpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case OpDecorateString: *hasResult = false; *hasResultType = false; break; - case OpDecorateStringGOOGLE: *hasResult = false; *hasResultType = false; break; case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; - case OpMemberDecorateStringGOOGLE: *hasResult = false; *hasResultType = false; break; case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; case OpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; case OpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; @@ -1860,6 +1903,8 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + case OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; } } #endif /* SPV_ENABLE_UTILITY_CODE */ diff --git a/Test/baseResults/spv.fsi.frag.out b/Test/baseResults/spv.fsi.frag.out new file mode 100644 index 00000000..51fb0688 --- /dev/null +++ b/Test/baseResults/spv.fsi.frag.out @@ -0,0 +1,56 @@ +spv.fsi.frag +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 24 + + Capability Shader + Capability CapabilityFragmentShaderSampleInterlockEXT + Extension "SPV_EXT_fragment_shader_interlock" + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + ExecutionMode 4 SampleInterlockOrderedEXT + Source GLSL 450 + SourceExtension "GL_ARB_fragment_shader_interlock" + Name 4 "main" + Name 7 "B1" + MemberName 7(B1) 0 "x" + Name 9 "b1" + Name 17 "im" + MemberDecorate 7(B1) 0 Coherent + MemberDecorate 7(B1) 0 Offset 0 + Decorate 7(B1) BufferBlock + Decorate 9(b1) DescriptorSet 0 + Decorate 9(b1) Binding 0 + Decorate 17(im) DescriptorSet 0 + Decorate 17(im) Binding 1 + Decorate 17(im) Coherent + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 1 + 7(B1): TypeStruct 6(int) + 8: TypePointer Uniform 7(B1) + 9(b1): 8(ptr) Variable Uniform + 10: 6(int) Constant 0 + 11: 6(int) Constant 1 + 12: TypePointer Uniform 6(int) + 14: TypeFloat 32 + 15: TypeImage 14(float) 2D nonsampled format:Rgba32f + 16: TypePointer UniformConstant 15 + 17(im): 16(ptr) Variable UniformConstant + 19: TypeVector 6(int) 2 + 20: 19(ivec2) ConstantComposite 10 10 + 21: TypeVector 14(float) 4 + 22: 14(float) Constant 0 + 23: 21(fvec4) ConstantComposite 22 22 22 22 + 4(main): 2 Function None 3 + 5: Label + BeginInvocationInterlockEXT + 13: 12(ptr) AccessChain 9(b1) 10 + Store 13 11 + 18: 15 Load 17(im) + ImageWrite 18 20 23 + EndInvocationInterlockEXT + Return + FunctionEnd diff --git a/Test/baseResults/spv.fsi_Error.frag.out b/Test/baseResults/spv.fsi_Error.frag.out new file mode 100644 index 00000000..4a03436d --- /dev/null +++ b/Test/baseResults/spv.fsi_Error.frag.out @@ -0,0 +1,14 @@ +spv.fsi_Error.frag +ERROR: 0:4: 'pixel_interlock_ordered' : can only apply to 'in' +ERROR: 0:7: 'pixel_interlock_unordered' : cannot change previously set fragment shader interlock ordering +ERROR: 0:11: '' : beginInvocationInterlockARB() must be in main() +ERROR: 0:12: '' : endInvocationInterlockARB() must be in main() +ERROR: 0:17: '' : endInvocationInterlockARB() must only be called once +ERROR: 0:18: '' : beginInvocationInterlockARB() must only be called once +ERROR: 0:18: '' : beginInvocationInterlockARB() must be called before endInvocationInterlockARB() +ERROR: 0:22: '' : endInvocationInterlockARB() cannot be placed after a return from main() +ERROR: 0:22: '' : endInvocationInterlockARB() must only be called once +ERROR: 9 compilation errors. No code generated. + + +SPIR-V is not generated for failed compile or link diff --git a/Test/spv.fsi.frag b/Test/spv.fsi.frag new file mode 100644 index 00000000..5e6fb5fe --- /dev/null +++ b/Test/spv.fsi.frag @@ -0,0 +1,20 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : enable + +layout(set = 0, binding = 0) coherent buffer B1 { + layout(offset = 0) int x; +} b1; + +layout(set = 0, binding = 1, rgba32f) coherent uniform image2D im; + +layout(sample_interlock_ordered) in; + +void main() { + + beginInvocationInterlockARB(); + + b1.x = 1; + imageStore(im, ivec2(0,0), vec4(0)); + + endInvocationInterlockARB(); +} diff --git a/Test/spv.fsi_Error.frag b/Test/spv.fsi_Error.frag new file mode 100644 index 00000000..adddf3e5 --- /dev/null +++ b/Test/spv.fsi_Error.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : enable + +layout(pixel_interlock_ordered) out; + +layout(pixel_interlock_ordered) in; +layout(pixel_interlock_unordered) in; + +void foo() +{ + beginInvocationInterlockARB(); + endInvocationInterlockARB(); +} + +void main() { + + endInvocationInterlockARB(); + beginInvocationInterlockARB(); + + return; + + endInvocationInterlockARB(); +} diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 90341dcb..1cbf4db7 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -422,6 +422,18 @@ enum TBlendEquationShift { EBlendCount }; +enum TInterlockOrdering { + EioNone, + EioPixelInterlockOrdered, + EioPixelInterlockUnordered, + EioSampleInterlockOrdered, + EioSampleInterlockUnordered, + EioShadingRateInterlockOrdered, + EioShadingRateInterlockUnordered, + + EioCount, +}; + class TQualifier { public: static const int layoutNotSet = -1; @@ -1110,6 +1122,18 @@ public: default: return 0; } } + static const char* getInterlockOrderingString(TInterlockOrdering order) + { + switch (order) { + case EioPixelInterlockOrdered: return "pixel_interlock_ordered"; + case EioPixelInterlockUnordered: return "pixel_interlock_unordered"; + case EioSampleInterlockOrdered: return "sample_interlock_ordered"; + case EioSampleInterlockUnordered: return "sample_interlock_unordered"; + case EioShadingRateInterlockOrdered: return "shading_rate_interlock_ordered"; + case EioShadingRateInterlockUnordered: return "shading_rate_interlock_unordered"; + default: return "none"; + } + } }; // Qualifiers that don't need to be keep per object. They have shader scope, not object scope. @@ -1130,6 +1154,7 @@ struct TShaderQualifiers { TLayoutDepth layoutDepth; bool blendEquation; // true if any blend equation was specified int numViews; // multiview extenstions + TInterlockOrdering interlockOrdering; #ifdef NV_EXTENSIONS bool layoutOverrideCoverage; // true if layout override_coverage set @@ -1165,6 +1190,7 @@ struct TShaderQualifiers { layoutDerivativeGroupLinear = false; primitives = TQualifier::layoutNotSet; #endif + interlockOrdering = EioNone; } // Merge in characteristics from the 'src' qualifier. They can override when @@ -1215,6 +1241,9 @@ struct TShaderQualifiers { if (src.primitives != TQualifier::layoutNotSet) primitives = src.primitives; #endif + + if (src.interlockOrdering != EioNone) + interlockOrdering = src.interlockOrdering; } }; diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index 89d19549..f7424e88 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -621,6 +621,9 @@ enum TOperator { EOpCooperativeMatrixStore, EOpCooperativeMatrixMulAdd, + EOpBeginInvocationInterlock, // Fragment only + EOpEndInvocationInterlock, // Fragment only + // // Branch // diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp index 16a2e1af..ecaf7556 100644 --- a/glslang/MachineIndependent/Initialize.cpp +++ b/glslang/MachineIndependent/Initialize.cpp @@ -5030,6 +5030,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + stageBuiltins[EShLangFragment].append( + "void beginInvocationInterlockARB(void);" + "void endInvocationInterlockARB(void);"); + #ifdef AMD_EXTENSIONS // GL_AMD_shader_explicit_vertex_parameter if (profile != EEsProfile && version >= 450) { @@ -9539,6 +9543,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion if (profile != EEsProfile) symbolTable.relateToOperator("interpolateAtVertexAMD", EOpInterpolateAtVertex); #endif + + symbolTable.relateToOperator("beginInvocationInterlockARB", EOpBeginInvocationInterlock); + symbolTable.relateToOperator("endInvocationInterlockARB", EOpEndInvocationInterlock); + break; case EShLangCompute: diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 8384eb96..569c9283 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -1410,6 +1410,44 @@ void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op) error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", ""); } break; + case EOpBeginInvocationInterlock: + if (language != EShLangFragment) + error(loc, "beginInvocationInterlockARB() must be in a fragment shader", "", ""); + if (! inMain) + error(loc, "beginInvocationInterlockARB() must be in main()", "", ""); + else if (postEntryPointReturn) + error(loc, "beginInvocationInterlockARB() cannot be placed after a return from main()", "", ""); + if (controlFlowNestingLevel > 0) + error(loc, "beginInvocationInterlockARB() cannot be placed within flow control", "", ""); + + if (beginInvocationInterlockCount > 0) + error(loc, "beginInvocationInterlockARB() must only be called once", "", ""); + if (endInvocationInterlockCount > 0) + error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", ""); + + beginInvocationInterlockCount++; + + // default to pixel_interlock_ordered + if (intermediate.getInterlockOrdering() == EioNone) + intermediate.setInterlockOrdering(EioPixelInterlockOrdered); + break; + case EOpEndInvocationInterlock: + if (language != EShLangFragment) + error(loc, "endInvocationInterlockARB() must be in a fragment shader", "", ""); + if (! inMain) + error(loc, "endInvocationInterlockARB() must be in main()", "", ""); + else if (postEntryPointReturn) + error(loc, "endInvocationInterlockARB() cannot be placed after a return from main()", "", ""); + if (controlFlowNestingLevel > 0) + error(loc, "endInvocationInterlockARB() cannot be placed within flow control", "", ""); + + if (endInvocationInterlockCount > 0) + error(loc, "endInvocationInterlockARB() must only be called once", "", ""); + if (beginInvocationInterlockCount == 0) + error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", ""); + + endInvocationInterlockCount++; + break; default: break; } @@ -4945,6 +4983,17 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi 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"); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 450, nullptr, "fragment shader interlock layout qualifier"); + requireExtensions(loc, 1, &E_GL_ARB_fragment_shader_interlock, TQualifier::getInterlockOrderingString(order)); + if (order == EioShadingRateInterlockOrdered || order == EioShadingRateInterlockUnordered) + requireExtensions(loc, 1, &E_GL_NV_shading_rate_image, TQualifier::getInterlockOrderingString(order)); + publicType.shaderQualifiers.interlockOrdering = order; + return; + } + } if (id.compare(0, 13, "blend_support") == 0) { bool found = false; for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) { @@ -5945,6 +5994,8 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "blend equation", ""); if (shaderQualifiers.numViews != TQualifier::layoutNotSet) error(loc, message, "num_views", ""); + if (shaderQualifiers.interlockOrdering != EioNone) + error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), ""); } // Correct and/or advance an object's offset layout qualifier. @@ -7874,6 +7925,14 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con if (publicType.qualifier.storage != EvqVaryingOut) error(loc, "can only apply to 'out'", "blend equation", ""); } + if (publicType.shaderQualifiers.interlockOrdering) { + if (publicType.qualifier.storage == EvqVaryingIn) { + if (!intermediate.setInterlockOrdering(publicType.shaderQualifiers.interlockOrdering)) + error(loc, "cannot change previously set fragment shader interlock ordering", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), ""); + } + else + error(loc, "can only apply to 'in'", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), ""); + } #ifdef NV_EXTENSIONS if (publicType.shaderQualifiers.layoutDerivativeGroupQuads && diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index a1ffe64d..04ede1e3 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -85,6 +85,7 @@ public: statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), postEntryPointReturn(false), contextPragma(true, false), + beginInvocationInterlockCount(0), endInvocationInterlockCount(0), parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr), limits(resources.limits), globalUniformBlock(nullptr), @@ -182,6 +183,8 @@ public: // the statementNestingLevel the current switch statement is at, which must match the level of its case statements TList switchLevel; struct TPragma contextPragma; + int beginInvocationInterlockCount; + int endInvocationInterlockCount; protected: TParseContextBase(TParseContextBase&); diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp index f19c3850..6c97da16 100644 --- a/glslang/MachineIndependent/Versions.cpp +++ b/glslang/MachineIndependent/Versions.cpp @@ -187,6 +187,7 @@ void TParseVersions::initializeExtensionBehavior() // extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members extensionBehavior[E_GL_ARB_post_depth_coverage] = EBhDisable; extensionBehavior[E_GL_ARB_shader_viewport_layer_array] = EBhDisable; + extensionBehavior[E_GL_ARB_fragment_shader_interlock] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_basic] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_vote] = EBhDisable; @@ -379,6 +380,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_ARB_shader_stencil_export 1\n" // "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members "#define GL_ARB_post_depth_coverage 1\n" + "#define GL_ARB_fragment_shader_interlock 1\n" "#define GL_EXT_shader_non_constant_global_initializers 1\n" "#define GL_EXT_shader_image_load_formatted 1\n" "#define GL_EXT_post_depth_coverage 1\n" diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h index bff08270..953d33a0 100644 --- a/glslang/MachineIndependent/Versions.h +++ b/glslang/MachineIndependent/Versions.h @@ -141,6 +141,7 @@ const char* const E_GL_ARB_shader_stencil_export = "GL_ARB_shader_stencil // const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members const char* const E_GL_ARB_post_depth_coverage = "GL_ARB_post_depth_coverage"; const char* const E_GL_ARB_shader_viewport_layer_array = "GL_ARB_shader_viewport_layer_array"; +const char* const E_GL_ARB_fragment_shader_interlock = "GL_ARB_fragment_shader_interlock"; const char* const E_GL_KHR_shader_subgroup_basic = "GL_KHR_shader_subgroup_basic"; const char* const E_GL_KHR_shader_subgroup_vote = "GL_KHR_shader_subgroup_vote"; diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index f9f285e4..abf5681b 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -1502,6 +1502,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) } infoSink.debug << "\n"; } + if (interlockOrdering != EioNone) + infoSink.debug << "interlock ordering = " << TQualifier::getInterlockOrderingString(interlockOrdering) << "\n"; break; #ifdef NV_EXTENSIONS diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index f29c93c0..30ba98db 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -240,7 +240,7 @@ public: invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false), - vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), + vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false), postDepthCoverage(false), depthLayout(EldNone), depthReplacing(false), hlslFunctionality1(false), blendEquations(0), xfbMode(false), multiStream(false), @@ -608,6 +608,15 @@ public: void setPointMode() { pointMode = true; } bool getPointMode() const { return pointMode; } + bool setInterlockOrdering(TInterlockOrdering o) + { + if (interlockOrdering != EioNone) + return interlockOrdering == o; + interlockOrdering = o; + return true; + } + TInterlockOrdering getInterlockOrdering() const { return interlockOrdering; } + bool setLocalSize(int dim, int size) { if (localSize[dim] > 1) @@ -826,6 +835,7 @@ protected: bool originUpperLeft; TVertexSpacing vertexSpacing; TVertexOrder vertexOrder; + TInterlockOrdering interlockOrdering; bool pointMode; int localSize[3]; int localSizeSpecId[3]; diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index 5a126f1d..ead5e6d2 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -319,6 +319,8 @@ INSTANTIATE_TEST_CASE_P( "spv.fragmentDensity.vert", "spv.fragmentDensity-es.frag", "spv.fragmentDensity-neg.frag", + "spv.fsi.frag", + "spv.fsi_Error.frag", "spv.fullyCovered.frag", "spv.functionCall.frag", "spv.functionNestedOpaque.vert", diff --git a/known_good.json b/known_good.json index 95f1f0ad..337a573d 100644 --- a/known_good.json +++ b/known_good.json @@ -5,14 +5,14 @@ "site" : "github", "subrepo" : "KhronosGroup/SPIRV-Tools", "subdir" : "External/spirv-tools", - "commit" : "9dfd4b8358077bdbe8e2f9388572b5376c370f5d" + "commit" : "2c0111e6eba779cf30e8c7f5a733ea0762895ba0" }, { "name" : "spirv-tools/external/spirv-headers", "site" : "github", "subrepo" : "KhronosGroup/SPIRV-Headers", "subdir" : "External/spirv-tools/external/spirv-headers", - "commit" : "4b0985f29277a81f5ce88feb0502cc44d6d5e7c3" + "commit" : "8b911bd2ba37677037b38c9bd286c7c05701bcda" } ] }