Merge remote-tracking branch 'origin' into pipeline-barriers-2.1
diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h
index 1a936ad..eeeef02 100644
--- a/MoltenVK/MoltenVK/API/mvk_datatypes.h
+++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h
@@ -390,18 +390,24 @@
 /** Returns the size, in bytes, of a vertex index of the specified type. */
 size_t mvkMTLIndexTypeSizeInBytes(MTLIndexType mtlIdxType);
 
-/** Returns the MVKShaderStage corresponding to the specified Vulkan VkShaderStageFlagBits. */
+/** Returns the MoltenVK MVKShaderStage corresponding to the specified Vulkan VkShaderStageFlagBits. */
 MVKShaderStage mvkShaderStageFromVkShaderStageFlagBits(VkShaderStageFlagBits vkStage);
 
-/** Returns the VkShaderStageFlagBits corresponding to the specified MoltenVK MVKShaderStage. */
+/** Returns the Vulkan VkShaderStageFlagBits corresponding to the specified MoltenVK MVKShaderStage. */
 VkShaderStageFlagBits mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage mvkStage);
 
-/** Returns the MTLWinding corresponding to the specified spv::ExecutionMode. */
+/** Returns the Metal MTLWinding corresponding to the specified SPIR-V spv::ExecutionMode. */
 MTLWinding mvkMTLWindingFromSpvExecutionMode(uint32_t spvMode);
 
-/** Returns the MTLTessellationPartitionMode corresponding to the specified spv::ExecutionMode. */
+/** Returns the Metal MTLTessellationPartitionMode corresponding to the specified SPIR-V spv::ExecutionMode. */
 MTLTessellationPartitionMode mvkMTLTessellationPartitionModeFromSpvExecutionMode(uint32_t spvMode);
 
+/** Returns the combination of Metal MTLRenderStage bits corresponding to the specified Vulkan VkPiplineStageFlags. */
+MTLRenderStages mvkMTLRenderStagesFromVkPipelineStageFlags(VkPipelineStageFlags vkStages);
+
+/** Returns the combination of Metal MTLBarrierScope bits corresponding to the specified Vulkan VkAccessFlags. */
+MTLBarrierScope mvkMTLBarrierScopeFromVkAccessFlags(VkAccessFlags vkAccess);
+
 #pragma mark -
 #pragma mark Geometry conversions
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index afe05ef..20c9495 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -65,8 +65,36 @@
 
 #if MVK_MACOS
     // Calls below invoke MTLBlitCommandEncoder so must apply this first
-	if ( !(_memoryBarriers.empty() && _imageMemoryBarriers.empty()) ) {
-		[cmdEncoder->_mtlRenderEncoder textureBarrier];
+	if ( [cmdEncoder->_mtlRenderEncoder respondsToSelector: @selector(memoryBarrierWithScope:afterStages:beforeStages:)] ) {
+		MTLRenderStages srcStages = mvkMTLRenderStagesFromVkPipelineStageFlags(_srcStageMask);
+		MTLRenderStages dstStages = mvkMTLRenderStagesFromVkPipelineStageFlags(_dstStageMask);
+		for (auto& mb : _memoryBarriers) {
+			MTLBarrierScope scope = mvkMTLBarrierScopeFromVkAccessFlags(mb.dstAccessMask);
+			scope |= mvkMTLBarrierScopeFromVkAccessFlags(mb.srcAccessMask);
+			[cmdEncoder->_mtlRenderEncoder memoryBarrierWithScope: scope
+													  afterStages: srcStages
+													 beforeStages: dstStages];
+		}
+		std::vector<id<MTLResource>> resources;
+		resources.reserve(_bufferMemoryBarriers.size() + _imageMemoryBarriers.size());
+		for (auto& mb : _bufferMemoryBarriers) {
+			auto* mvkBuff = (MVKBuffer*)mb.buffer;
+			resources.push_back(mvkBuff->getMTLBuffer());
+		}
+		for (auto& mb : _imageMemoryBarriers) {
+			auto* mvkImg = (MVKImage*)mb.image;
+			resources.push_back(mvkImg->getMTLTexture());
+		}
+		if ( !resources.empty() ) {
+			[cmdEncoder->_mtlRenderEncoder memoryBarrierWithResources: resources.data()
+																count: resources.size()
+														  afterStages: srcStages
+														 beforeStages: dstStages];
+		}
+	} else {
+		if ( !(_memoryBarriers.empty() && _imageMemoryBarriers.empty()) ) {
+			[cmdEncoder->_mtlRenderEncoder textureBarrier];
+		}
 	}
 #endif
 
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index 5b8bb2e..b6a764c 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -1268,6 +1268,33 @@
 	}
 }
 
+MVK_PUBLIC_SYMBOL MTLRenderStages mvkMTLRenderStagesFromVkPipelineStageFlags(VkPipelineStageFlags vkStages) {
+	MTLRenderStages mtlStages = MTLRenderStages(0);
+	if ( mvkIsAnyFlagEnabled(vkStages, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT) ) {
+		mtlStages |= MTLRenderStageVertex;
+	}
+	if ( mvkIsAnyFlagEnabled(vkStages, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ) ) {
+		mtlStages |= MTLRenderStageFragment;
+	}
+	return mtlStages;
+}
+
+MVK_PUBLIC_SYMBOL MTLBarrierScope mvkMTLBarrierScopeFromVkAccessFlags(VkAccessFlags vkAccess) {
+	MTLBarrierScope mtlScope = MTLBarrierScope(0);
+	if ( mvkIsAnyFlagEnabled(vkAccess, VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT) ) {
+		mtlScope |= MTLBarrierScopeBuffers;
+	}
+	if ( mvkIsAnyFlagEnabled(vkAccess, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT) ) {
+		mtlScope |= MTLBarrierScopeBuffers | MTLBarrierScopeTextures;
+	}
+#if MVK_MACOS
+	if ( mvkIsAnyFlagEnabled(vkAccess, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT) ) {
+		mtlScope |= MTLBarrierScopeRenderTargets;
+	}
+#endif
+	return mtlScope;
+}
+
 
 #pragma mark -
 #pragma mark Memory options