Merge pull request #734 from cdavis5e/fragment-shader-interlock

Support the VK_EXT_fragment_shader_interlock extension.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 8fc20af..9bd6595 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -254,6 +254,7 @@
 - `VK_EXT_debug_marker`
 - `VK_EXT_debug_report`
 - `VK_EXT_debug_utils`
+- `VK_EXT_fragment_shader_interlock` *(requires Metal 2.0 and Raster Order Groups)*
 - `VK_EXT_host_query_reset`
 - `VK_EXT_memory_budget` *(requires Metal 2.0)*
 - `VK_EXT_metal_surface`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 6ad0843..ad000f4 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -20,6 +20,7 @@
 
 - Add support for extensions:
 	- `VK_KHR_device_group`
+	- `VK_EXT_fragment_shader_interlock`
 - Add support for `VkEvent`, using either native `MTLEvent` or emulation when `MTLEvent` not available.
 - `vkInvalidateMappedMemoryRanges()` synchronizes managed device memory to CPU.
 - Track supported instance and device extensions correctly.
@@ -44,7 +45,27 @@
   `MVKConfiguration::presentWithCommandBuffer` is now obsolete.
 - Don't use `MTLCommandBuffer push/popDebugGroup` if not available.
 - Add ability to automatically cause an *Xcode* GPU capture without developer intervention.
+- On macOS, limit uniform buffer bindings to 64k.
 - Update `VK_MVK_MOLTENVK_SPEC_VERSION` to version 22.
+- Update to latest SPIRV-Cross version:
+	- MSL: Deal with array copies from and to threadgroup.
+	- MSL: Inline all emitted functions.
+	- MSL: Inline all non-entry-point functions.
+	- MSL: Add `{Base,}{Vertex,Instance}{,Index}` to `bitcast_from_builtin_load`.
+	- MSL: Add support for sampler Y'CbCr conversion.
+	- MSL: Force storage images on iOS to use discrete descriptors.
+	- MSL: Support dynamic offsets for buffers in argument buffers.
+	- Support the `SPV_EXT_fragment_shader_interlock` extension.
+	- Fix variable scope when switch block exits multiple times.
+	- Deal correctly with sign on bitfield operations.
+	- Elide branches to continue block when continue block is also a merge.
+	- Move branchless analysis to CFG.
+	- Deal with `ldexp` taking `uint` input.
+	- Do not allow base expressions for non-native row-major matrices.
+	- GLSL: Assume image and sampler can be `RelaxedPrecision`.
+	- GLSL: Fix post-depth coverage for ESSL.
+	- Fix `ParsedIR::mark_used_as_array_length(uint32_t id)`.
+	- Refactor into stronger types in public API.
 
 
 
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index fc4d9eb..999ffa7 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-4ce04480ec5469fe7ebbdd66c3016090a704d81b
+2082e7e80189843a52d9a79bc17787af93b517de
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index fbd7978..3b5af92 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -547,6 +547,7 @@
 	VkBool32 textureBuffers;					/**< If true, textures of type MTLTextureTypeBuffer are supported. */
 	VkBool32 postDepthCoverage;					/**< If true, coverage masks in fragment shaders post-depth-test are supported. */
 	VkBool32 fences;							/**< If true, Metal synchronization fences (MTLFence) are supported. */
+	VkBool32 rasterOrderGroups;					/**< If true, Raster order groups in fragment shaders are supported. */
 } MVKPhysicalDeviceMetalFeatures;
 
 /**
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 6649ba0..adbc3b2 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -638,6 +638,7 @@
 	const VkPhysicalDeviceFloat16Int8FeaturesKHR _enabledF16I8Features;
 	const VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR _enabledUBOLayoutFeatures;
 	const VkPhysicalDeviceVariablePointerFeatures _enabledVarPtrFeatures;
+	const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT _enabledInterlockFeatures;
 	const VkPhysicalDeviceHostQueryResetFeaturesEXT _enabledHostQryResetFeatures;
 	const VkPhysicalDeviceScalarBlockLayoutFeaturesEXT _enabledScalarLayoutFeatures;
 	const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT _enabledTexelBuffAlignFeatures;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index bc89164..2456bfa 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -102,6 +102,13 @@
                     varPtrFeatures->variablePointers = true;
                     break;
                 }
+                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
+                    auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
+                    interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
+                    interlockFeatures->fragmentShaderPixelInterlock = _metalFeatures.rasterOrderGroups;
+                    interlockFeatures->fragmentShaderShadingRateInterlock = false;    // Requires variable rate shading; not supported yet in Metal
+                    break;
+                }
                 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: {
                     auto* hostQueryResetFeatures = (VkPhysicalDeviceHostQueryResetFeaturesEXT*)next;
                     hostQueryResetFeatures->hostQueryReset = true;
@@ -861,6 +868,11 @@
 
 #endif
 
+    // Note the selector name, which is different from the property name.
+    if ( [_mtlDevice respondsToSelector: @selector(areRasterOrderGroupsSupported)] ) {
+        _metalFeatures.rasterOrderGroups = _mtlDevice.rasterOrderGroupsSupported;
+    }
+
     if ( [_mtlDevice respondsToSelector: @selector(maxBufferLength)] ) {
         _metalFeatures.maxMTLBufferSize = _mtlDevice.maxBufferLength;
     }
@@ -1652,6 +1664,9 @@
 	MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_supportedExtensions;
 	pWritableExtns->disableAllButEnabledDeviceExtensions();
 
+	if (!_metalFeatures.rasterOrderGroups) {
+		pWritableExtns->vk_EXT_fragment_shader_interlock.enabled = false;
+	}
 	if (!_metalFeatures.postDepthCoverage) {
 		pWritableExtns->vk_EXT_post_depth_coverage.enabled = false;
 	}
@@ -2295,6 +2310,7 @@
 	_enabledF16I8Features(),
 	_enabledUBOLayoutFeatures(),
 	_enabledVarPtrFeatures(),
+	_enabledInterlockFeatures(),
 	_enabledHostQryResetFeatures(),
 	_enabledScalarLayoutFeatures(),
 	_enabledTexelBuffAlignFeatures(),
@@ -2409,6 +2425,7 @@
 	memset((void*)&_enabledF16I8Features, 0, sizeof(_enabledF16I8Features));
 	memset((void*)&_enabledUBOLayoutFeatures, 0, sizeof(_enabledUBOLayoutFeatures));
 	memset((void*)&_enabledVarPtrFeatures, 0, sizeof(_enabledVarPtrFeatures));
+	memset((void*)&_enabledInterlockFeatures, 0, sizeof(_enabledInterlockFeatures));
 	memset((void*)&_enabledHostQryResetFeatures, 0, sizeof(_enabledHostQryResetFeatures));
 	memset((void*)&_enabledScalarLayoutFeatures, 0, sizeof(_enabledScalarLayoutFeatures));
 	memset((void*)&_enabledTexelBuffAlignFeatures, 0, sizeof(_enabledTexelBuffAlignFeatures));
@@ -2436,9 +2453,13 @@
 	pdHostQryResetFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT;
 	pdHostQryResetFeatures.pNext = &pdScalarLayoutFeatures;
 
+	VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT pdInterlockFeatures;
+	pdInterlockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT;
+	pdInterlockFeatures.pNext = &pdHostQryResetFeatures;
+
 	VkPhysicalDeviceVariablePointerFeatures pdVarPtrFeatures;
 	pdVarPtrFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
-	pdVarPtrFeatures.pNext = &pdHostQryResetFeatures;
+	pdVarPtrFeatures.pNext = &pdInterlockFeatures;
 
 	VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR pdUBOLayoutFeatures;
 	pdUBOLayoutFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR;
@@ -2514,6 +2535,13 @@
 							   &pdVarPtrFeatures.variablePointersStorageBuffer, 2);
 				break;
 			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
+				auto* requestedFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
+				enableFeatures(&_enabledInterlockFeatures.fragmentShaderSampleInterlock,
+							   &requestedFeatures->fragmentShaderSampleInterlock,
+							   &pdInterlockFeatures.fragmentShaderSampleInterlock, 3);
+				break;
+			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: {
 				auto* requestedFeatures = (VkPhysicalDeviceHostQueryResetFeaturesEXT*)next;
 				enableFeatures(&_enabledHostQryResetFeatures.hostQueryReset,
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 8f8ab03..9a2a320 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -67,6 +67,7 @@
 MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, MVK_EXTENSION_DEVICE)
 MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, MVK_EXTENSION_INSTANCE)
 MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, MVK_EXTENSION_INSTANCE)
+MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, MVK_EXTENSION_DEVICE)
 MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, MVK_EXTENSION_DEVICE)
 MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, MVK_EXTENSION_DEVICE)
 MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, MVK_EXTENSION_INSTANCE)
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
index 1a670ee..7d069b8 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
@@ -47,6 +47,9 @@
 // Returns whether the specified properties are valid for this platform
 static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
 #if MVK_MACOS
+	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) {
+		return mvkOSVersion() >= 10.13;
+	}
 	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
 		return mvkOSVersion() >= 10.13;
 	}
@@ -66,6 +69,9 @@
 #endif
 #if MVK_IOS
 	if (pProperties == &kVkExtProps_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE) { return false; }
+	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) {
+		return mvkOSVersion() >= 11.0;
+	}
 	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
 		return mvkOSVersion() >= 11.0;
 	}
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
index e331486..59790c3 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
@@ -425,7 +425,7 @@
 													 uint32_t size,
 													 SPIRV_CROSS_NAMESPACE::SpecializationConstant& spvSpecConst) {
 	wgDim.size = max(size, 1u);
-	wgDim.isSpecialized = (spvSpecConst.id != 0);
+	wgDim.isSpecialized = (uint32_t(spvSpecConst.id) != 0);
 	wgDim.specializationID = spvSpecConst.constant_id;
 }