Support the VK_EXT_fragment_shader_interlock extension.

This extension allows fragment shaders to delineate critical sections
where pairs of invocations may not execute simultaneously. In Metal, the
nearest equivalent functionality is raster order groups. This
implementation is thus implemented on top of them.

Update SPIRV-Cross to pull in SPIR-V support for this new 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 513252f..372724b 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;
     }
@@ -1648,6 +1660,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;
 	}
@@ -2291,6 +2306,7 @@
 	_enabledF16I8Features(),
 	_enabledUBOLayoutFeatures(),
 	_enabledVarPtrFeatures(),
+	_enabledInterlockFeatures(),
 	_enabledHostQryResetFeatures(),
 	_enabledScalarLayoutFeatures(),
 	_enabledTexelBuffAlignFeatures(),
@@ -2405,6 +2421,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));
@@ -2432,9 +2449,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;
@@ -2510,6 +2531,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;
 }