Validate format capabilities for MSAA, renderpass attachments, and vkCmdResolveImage().

vkGetPhysicalDeviceImageFormatProperties() tests whether format supports MSAA.
vkCreateRenderPass() validate each attachment supports format capabilities required
by each subpass that uses it.
vkCmdResolveImage() validate that destination attachment supports being resolved to.
MVKPixelFormats add getVkFormatCapabilities(), getMTLPixelFormatCapabilities(),
and vkFormatIsSupportedOrSubstitutable().
Rework type handling in flag functions in MVKFoundation.h.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 6cbc403..eea6263 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -21,6 +21,7 @@
 
 - Accurately populate Vulkan `VkFormatProperties` from `MTLPixelFormat` capabilities, 
   taking into consideration variations across `MTLDevice` Features Sets.
+- Validate format capabilities for MSAA, renderpass attachments, and `vkCmdResolveImage()`.
 - Fix issue where immutable samplers are removed during descriptor update.
 - Guard against Metal validation assertion from reuse of query number within a single `MTLRenderEncoder`.
 - Increase value of `VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment` 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 5db0911..f23b2eb 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -467,6 +467,11 @@
 
     _dstImage->getTransferDescriptorData(_transferImageData);
 	_transferImageData.samples = _srcImage->getSampleCount();
+
+	// Validate
+	if ( !mvkAreAllFlagsEnabled(getPixelFormats()->getMTLPixelFormatCapabilities(_dstImage->getMTLPixelFormat()), kMVKMTLFmtCapsResolve) ) {
+		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", getPixelFormats()->getVkFormatName(_dstImage->getVkFormat())));
+	}
 }
 
 /**
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 33e3369..26a6ad5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -223,11 +223,11 @@
 }
 
 VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
-                                                     VkImageType type,
-                                                     VkImageTiling tiling,
-                                                     VkImageUsageFlags usage,
-                                                     VkImageCreateFlags flags,
-                                                     VkImageFormatProperties* pImageFormatProperties) {
+													 VkImageType type,
+													 VkImageTiling tiling,
+													 VkImageUsageFlags usage,
+													 VkImageCreateFlags flags,
+													 VkImageFormatProperties* pImageFormatProperties) {
 
 	if ( !_pixelFormats.vkFormatIsSupported(format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 
@@ -245,14 +245,16 @@
 														  VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
 														  VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
 
-    VkPhysicalDeviceLimits* pLimits = &_properties.limits;
-    VkExtent3D maxExt;
-	uint32_t maxLevels;
+	VkPhysicalDeviceLimits* pLimits = &_properties.limits;
+	VkExtent3D maxExt = { 1, 1, 1};
+	uint32_t maxLevels = 1;
 	uint32_t maxLayers = hasAttachmentUsage ? pLimits->maxFramebufferLayers : pLimits->maxImageArrayLayers;
 
-	VkSampleCountFlags sampleCounts = _metalFeatures.supportedSampleCounts;
-    switch (type) {
-        case VK_IMAGE_TYPE_1D:
+	bool supportsMSAA =  mvkAreAllFlagsEnabled(_pixelFormats.getVkFormatCapabilities(format), kMVKMTLFmtCapsMSAA);
+	VkSampleCountFlags sampleCounts = supportsMSAA ? _metalFeatures.supportedSampleCounts : VK_SAMPLE_COUNT_1_BIT;
+
+	switch (type) {
+		case VK_IMAGE_TYPE_1D:
 			maxExt.height = 1;
 			maxExt.depth = 1;
 			if (mvkTreatTexture1DAs2D()) {
@@ -273,16 +275,17 @@
 				if (mvkFmt == kMVKFormatDepthStencil) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 				if (mvkFmt == kMVKFormatCompressed) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 			}
-            break;
-        case VK_IMAGE_TYPE_2D:
-            if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
-                maxExt.width = pLimits->maxImageDimensionCube;
-                maxExt.height = pLimits->maxImageDimensionCube;
-            } else {
-                maxExt.width = pLimits->maxImageDimension2D;
-                maxExt.height = pLimits->maxImageDimension2D;
-            }
-            maxExt.depth = 1;
+			break;
+
+		case VK_IMAGE_TYPE_2D:
+			if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
+				maxExt.width = pLimits->maxImageDimensionCube;
+				maxExt.height = pLimits->maxImageDimensionCube;
+			} else {
+				maxExt.width = pLimits->maxImageDimension2D;
+				maxExt.height = pLimits->maxImageDimension2D;
+			}
+			maxExt.depth = 1;
 			if (tiling == VK_IMAGE_TILING_LINEAR) {
 				// Linear textures have additional restrictions under Metal:
 				// - They may not be depth/stencil or compressed textures.
@@ -310,12 +313,13 @@
 				}
 				maxLevels = mvkMipmapLevels3D(maxExt);
 			}
-            break;
-        case VK_IMAGE_TYPE_3D:
-            // Metal does not allow linear tiling on 3D textures
-            if (tiling == VK_IMAGE_TILING_LINEAR) {
-                return VK_ERROR_FORMAT_NOT_SUPPORTED;
-            }
+			break;
+
+		case VK_IMAGE_TYPE_3D:
+			// Metal does not allow linear tiling on 3D textures
+			if (tiling == VK_IMAGE_TILING_LINEAR) {
+				return VK_ERROR_FORMAT_NOT_SUPPORTED;
+			}
 			// Metal does not allow compressed or depth/stencil formats on 3D textures
 			if (mvkFmt == kMVKFormatDepthStencil
 #if MVK_IOS
@@ -330,35 +334,25 @@
 				return VK_ERROR_FORMAT_NOT_SUPPORTED;
 			}
 #endif
-            maxExt.width = pLimits->maxImageDimension3D;
-            maxExt.height = pLimits->maxImageDimension3D;
-            maxExt.depth = pLimits->maxImageDimension3D;
+			maxExt.width = pLimits->maxImageDimension3D;
+			maxExt.height = pLimits->maxImageDimension3D;
+			maxExt.depth = pLimits->maxImageDimension3D;
 			maxLevels = mvkMipmapLevels3D(maxExt);
-            maxLayers = 1;
-            sampleCounts = VK_SAMPLE_COUNT_1_BIT;
-            break;
-        default:
-			// Metal does not allow linear tiling on anything but 2D textures
-			if (tiling == VK_IMAGE_TILING_LINEAR) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
-
-			// Metal does not allow compressed or depth/stencil formats on anything but 2D textures
-			if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed) {
-				return VK_ERROR_FORMAT_NOT_SUPPORTED;
-			}
-            maxExt = { 1, 1, 1};
-            maxLayers = 1;
-			maxLevels = 1;
+			maxLayers = 1;
 			sampleCounts = VK_SAMPLE_COUNT_1_BIT;
-            break;
-    }
+			break;
 
-    pImageFormatProperties->maxExtent = maxExt;
-    pImageFormatProperties->maxMipLevels = maxLevels;
-    pImageFormatProperties->maxArrayLayers = maxLayers;
-    pImageFormatProperties->sampleCounts = sampleCounts;
-    pImageFormatProperties->maxResourceSize = kMVKUndefinedLargeUInt64;
+		default:
+			return VK_ERROR_FORMAT_NOT_SUPPORTED;	// Illegal VkImageType
+	}
 
-    return VK_SUCCESS;
+	pImageFormatProperties->maxExtent = maxExt;
+	pImageFormatProperties->maxMipLevels = maxLevels;
+	pImageFormatProperties->maxArrayLayers = maxLayers;
+	pImageFormatProperties->sampleCounts = sampleCounts;
+	pImageFormatProperties->maxResourceSize = kMVKUndefinedLargeUInt64;
+
+	return VK_SUCCESS;
 }
 
 VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
index 0cfd711..c01d950 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
@@ -87,10 +87,14 @@
 	bool hasReportedSubstitution;
 
 	inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); };
+
 	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid); };
 	inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlPixelFormatSubstitute != MTLPixelFormatInvalid); };
+	inline MTLPixelFormat getMTLPixelFormatOrSubstitute() const { return mtlPixelFormat ? mtlPixelFormat : mtlPixelFormatSubstitute; }
+
 	inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); };
 	inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); };
+	inline MTLVertexFormat getMTLVertexFormatOrSubstitute() const { return mtlVertexFormat ? mtlVertexFormat : mtlVertexFormatSubstitute; }
 } MVKVkFormatDesc;
 
 /** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */
@@ -121,6 +125,9 @@
 	/** Returns whether the VkFormat is supported by this implementation. */
 	bool vkFormatIsSupported(VkFormat vkFormat);
 
+	/** Returns whether the VkFormat is supported by this implementation, or can be substituted by one that is. */
+	bool vkFormatIsSupportedOrSubstitutable(VkFormat vkFormat);
+
 	/** Returns whether the MTLPixelFormat is supported by this implementation. */
 	bool mtlPixelFormatIsSupported(MTLPixelFormat mtlFormat);
 
@@ -225,6 +232,12 @@
 	/** Returns the default properties for the specified Vulkan format. */
 	VkFormatProperties getVkFormatProperties(VkFormat vkFormat);
 
+	/** Returns the Metal format capabilities supported by the specified Vulkan format. */
+	MVKMTLFmtCaps getVkFormatCapabilities(VkFormat vkFormat);
+
+	/** Returns the Metal format capabilities supported by the specified Metal format. */
+	MVKMTLFmtCaps getMTLPixelFormatCapabilities(MTLPixelFormat mtlFormat);
+
 	/** Returns the name of the specified Vulkan format. */
 	const char* getVkFormatName(VkFormat vkFormat);
 
@@ -266,7 +279,9 @@
 protected:
 	MVKVkFormatDesc& getVkFormatDesc(VkFormat vkFormat);
 	MVKVkFormatDesc& getVkFormatDesc(MTLPixelFormat mtlFormat);
+	MVKMTLFormatDesc& getMTLPixelFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLPixelFormatDesc(MTLPixelFormat mtlFormat);
+	MVKMTLFormatDesc& getMTLVertexFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLVertexFormatDesc(MTLVertexFormat mtlFormat);
 	VkFormatFeatureFlags getOptimalTilingFeatures(MVKMTLFmtCaps mtlFmtCaps);
 	VkFormatFeatureFlags getLinearTilingFeatures(MVKMTLFmtCaps mtlFmtCaps, MVKFormatType mvkFmtType);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
index dc98f54..a8526de 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -120,6 +120,10 @@
 	return getVkFormatDesc(vkFormat).isSupported();
 }
 
+bool MVKPixelFormats::vkFormatIsSupportedOrSubstitutable(VkFormat vkFormat) {
+	return getVkFormatDesc(vkFormat).isSupportedOrSubstitutable();
+}
+
 bool MVKPixelFormats::mtlPixelFormatIsSupported(MTLPixelFormat mtlFormat) {
 	return getMTLPixelFormatDesc(mtlFormat).isSupported();
 }
@@ -260,6 +264,14 @@
 	return	getVkFormatDesc(vkFormat).properties;
 }
 
+MVKMTLFmtCaps MVKPixelFormats::getVkFormatCapabilities(VkFormat vkFormat) {
+	return getMTLPixelFormatDesc(vkFormat).mtlFmtCaps;
+}
+
+MVKMTLFmtCaps MVKPixelFormats::getMTLPixelFormatCapabilities(MTLPixelFormat mtlFormat) {
+	return getMTLPixelFormatDesc(mtlFormat).mtlFmtCaps;
+}
+
 const char* MVKPixelFormats::getVkFormatName(VkFormat vkFormat) {
     return getVkFormatDesc(vkFormat).name;
 }
@@ -389,23 +401,33 @@
 	return _vkFormatDescriptions[fmtIdx];
 }
 
+// Return a reference to the Vulkan format descriptor corresponding to the MTLPixelFormat.
+MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(MTLPixelFormat mtlFormat) {
+	return getVkFormatDesc(getMTLPixelFormatDesc(mtlFormat).vkFormat);
+}
+
+// Return a reference to the Metal format descriptor corresponding to the VkFormat.
+MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(VkFormat vkFormat) {
+	return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).getMTLPixelFormatOrSubstitute());
+}
+
 // Return a reference to the Metal format descriptor corresponding to the MTLPixelFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(MTLPixelFormat mtlFormat) {
 	uint16_t fmtIdx = (mtlFormat < _mtlPixelFormatCount) ? _mtlFormatDescIndicesByMTLPixelFormats[mtlFormat] : 0;
 	return _mtlPixelFormatDescriptions[fmtIdx];
 }
 
+// Return a reference to the Metal format descriptor corresponding to the VkFormat.
+MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(VkFormat vkFormat) {
+	return getMTLVertexFormatDesc(getVkFormatDesc(vkFormat).getMTLVertexFormatOrSubstitute());
+}
+
 // Return a reference to the Metal format descriptor corresponding to the MTLVertexFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(MTLVertexFormat mtlFormat) {
 	uint16_t fmtIdx = (mtlFormat < _mtlVertexFormatCount) ? _mtlFormatDescIndicesByMTLVertexFormats[mtlFormat] : 0;
 	return _mtlVertexFormatDescriptions[fmtIdx];
 }
 
-// Return a reference to the Vulkan format descriptor corresponding to the MTLPixelFormat.
-MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(MTLPixelFormat mtlFormat) {
-	return getVkFormatDesc(getMTLPixelFormatDesc(mtlFormat).vkFormat);
-}
-
 
 #pragma mark Construction
 
@@ -973,8 +995,7 @@
 													MTLPixelFormat mtlPixFmt,
 													MVKMTLFmtCaps mtlFmtCaps) {
 	if ( [mtlDevice supportsFeatureSet: mtlFeatSet] ) {
-		auto& fmtDesc = getMTLPixelFormatDesc(mtlPixFmt);
-		fmtDesc.mtlFmtCaps = (MVKMTLFmtCaps)(fmtDesc.mtlFmtCaps | mtlFmtCaps);
+		mvkEnableFlags(getMTLPixelFormatDesc(mtlPixFmt).mtlFmtCaps, mtlFmtCaps);
 	}
 }
 
@@ -984,8 +1005,7 @@
 													 MTLVertexFormat mtlVtxFmt,
 													 MVKMTLFmtCaps mtlFmtCaps) {
 	if ( [mtlDevice supportsFeatureSet: mtlFeatSet] ) {
-		auto& fmtDesc = getMTLVertexFormatDesc(mtlVtxFmt);
-		fmtDesc.mtlFmtCaps = (MVKMTLFmtCaps)(fmtDesc.mtlFmtCaps | mtlFmtCaps);
+		mvkEnableFlags(getMTLVertexFormatDesc(mtlVtxFmt).mtlFmtCaps, mtlFmtCaps);
 	}
 }
 
@@ -1159,8 +1179,8 @@
 
 			// Vulkan format features
 			MVKFormatType fmtType = vkDesc.formatType;
-			MVKMTLFmtCaps mtlPixFmtCaps = getMTLPixelFormatDesc(vkDesc.mtlPixelFormat ?: vkDesc.mtlPixelFormatSubstitute).mtlFmtCaps;
-			MVKMTLFmtCaps mtlVtxFmtCaps = getMTLVertexFormatDesc(vkDesc.mtlVertexFormat ?: vkDesc.mtlVertexFormatSubstitute).mtlFmtCaps;
+			MVKMTLFmtCaps mtlPixFmtCaps = getMTLPixelFormatDesc(vkFmt).mtlFmtCaps;
+			MVKMTLFmtCaps mtlVtxFmtCaps = getMTLVertexFormatDesc(vkFmt).mtlFmtCaps;
 			vkDesc.properties = { getLinearTilingFeatures(mtlPixFmtCaps, fmtType),
 								  getOptimalTilingFeatures(mtlPixFmtCaps),
 								  getBufferFeatures(mtlPixFmtCaps, mtlVtxFmtCaps, fmtType) };
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index f3eab2f..9c73c45 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -84,7 +84,7 @@
 	friend class MVKRenderPass;
 	friend class MVKRenderPassAttachment;
 
-	bool isUsingAttachmentAt(uint32_t rpAttIdx);
+	MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx);
 
 	MVKRenderPass* _renderPass;
 	uint32_t _subpassIndex;
@@ -134,8 +134,6 @@
 							const VkAttachmentDescription* pCreateInfo);
 
 protected:
-	VkAttachmentDescription validate(const VkAttachmentDescription* pCreateInfo);
-
 	VkAttachmentDescription _info;
 	MVKRenderPass* _renderPass;
 	uint32_t _attachmentIndex;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 09b8344..ecf02cd 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -197,24 +197,33 @@
 	}
 }
 
-/**
- * Returns whether this subpass uses the attachment at the specified index within the
- * parent renderpass, as any of input, color, resolve, or depth/stencil attachment type.
- */
-bool MVKRenderSubpass::isUsingAttachmentAt(uint32_t rpAttIdx) {
+//Returns the format capabilities required by this render subpass.
+// The Vulkan spec is unclear about whether a subpass can use an attachment in multiple places,
+// so accumulate the capabilities from all possible attachments, just to be safe.
+MVKMTLFmtCaps MVKRenderSubpass::getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx) {
+	MVKMTLFmtCaps caps = kMVKMTLFmtCapsNone;
 
 	for (auto& att : _inputAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsNone);	// TODO: input attachments are current unsupported
+			break;
+		}
 	}
 	for (auto& att : _colorAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsColorAtt);
+			break;
+		}
 	}
 	for (auto& att : _resolveAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsResolve);
+			break;
+		}
 	}
-	if (_depthStencilAttachment.attachment == rpAttIdx) { return true; }
+	if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); }
 
-	return false;
+	return caps;
 }
 
 MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
@@ -310,33 +319,35 @@
 
 MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
 												 const VkAttachmentDescription* pCreateInfo) {
+	_info = *pCreateInfo;
 	_renderPass = renderPass;
 	_attachmentIndex = uint32_t(_renderPass->_attachments.size());
 
-	// Determine the indices of the first and last render subpasses to use that attachment.
+	// Validate pixel format is supported
+	MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
+	if ( !pixFmts->vkFormatIsSupportedOrSubstitutable(_info.format) ) {
+		_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s is not supported on this device.", _renderPass->getPixelFormats()->getVkFormatName(_info.format)));
+	}
+
+	// Determine the indices of the first and last render subpasses to use this attachment.
 	_firstUseSubpassIdx = kMVKUndefinedLargeUInt32;
 	_lastUseSubpassIdx = 0;
 	for (auto& subPass : _renderPass->_subpasses) {
-		if (subPass.isUsingAttachmentAt(_attachmentIndex)) {
+		// If it uses this attachment, the subpass will identify required format capabilities.
+		MVKMTLFmtCaps reqCaps = subPass.getRequiredFormatCapabilitiesForAttachmentAt(_attachmentIndex);
+		if (reqCaps) {
 			uint32_t spIdx = subPass._subpassIndex;
-			_firstUseSubpassIdx = MIN(spIdx, _firstUseSubpassIdx);
-			_lastUseSubpassIdx = MAX(spIdx, _lastUseSubpassIdx);
+			_firstUseSubpassIdx = min(spIdx, _firstUseSubpassIdx);
+			_lastUseSubpassIdx = max(spIdx, _lastUseSubpassIdx);
+
+			// Validate that the attachment pixel format supports the capabilities required by the subpass.
+			if ( !mvkAreAllFlagsEnabled(pixFmts->getVkFormatCapabilities(_info.format), reqCaps) ) {
+				_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s on this device does not support the VkFormat attachment capabilities required by the subpass at index %d.", _renderPass->getPixelFormats()->getVkFormatName(_info.format), spIdx));
+			}
 		}
 	}
-
-	_info = validate(pCreateInfo);
 }
 
-// Validate and potentially modify the create info
-VkAttachmentDescription MVKRenderPassAttachment::validate(const VkAttachmentDescription* pCreateInfo) {
-	VkAttachmentDescription info = *pCreateInfo;
-
-	if ( !_renderPass->getPixelFormats()->getMTLPixelFormatFromVkFormat(info.format) ) {
-		_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s is not supported on this device.", _renderPass->getPixelFormats()->getVkFormatName(info.format)));
-	}
-
-	return info;
-}
 
 #pragma mark -
 #pragma mark MVKRenderPass
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index 4c532ff..c256bf0 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -497,26 +497,26 @@
 #pragma mark Boolean flags
 
 /** Enables the flags (sets bits to 1) within the value parameter specified by the bitMask parameter. */
-template<typename T1, typename T2>
-void mvkEnableFlags(T1& value, const T2 bitMask) { value |= bitMask; }
+template<typename Tv, typename Tm>
+void mvkEnableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value | bitMask); }
 
 /** Disables the flags (sets bits to 0) within the value parameter specified by the bitMask parameter. */
-template<typename T1, typename T2>
-void mvkDisableFlags(T1& value, const T2 bitMask) { value &= ~bitMask; }
+template<typename Tv, typename Tm>
+void mvkDisableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value & ~(Tv)bitMask); }
 
 /** Returns whether the specified value has ANY of the flags specified in bitMask enabled (set to 1). */
-template<typename T1, typename T2>
-bool mvkIsAnyFlagEnabled(T1 value, const T2 bitMask) { return !!(value & bitMask); }
+template<typename Tv, typename Tm>
+bool mvkIsAnyFlagEnabled(Tv value, const Tm bitMask) { return !!(value & bitMask); }
 
 /** Returns whether the specified value has ALL of the flags specified in bitMask enabled (set to 1). */
-template<typename T1, typename T2>
-bool mvkAreAllFlagsEnabled(T1 value, const T2 bitMask) { return ((value & bitMask) == bitMask); }
+template<typename Tv, typename Tm>
+bool mvkAreAllFlagsEnabled(Tv value, const Tm bitMask) { return ((value & bitMask) == bitMask); }
 
 /** Returns whether the specified value has ONLY one or more of the flags specified in bitMask enabled (set to 1), and none others. */
-template<typename T1, typename T2>
-bool mvkIsOnlyAnyFlagEnabled(T1 value, const T2 bitMask) { return (mvkIsAnyFlagEnabled(value, bitMask) && ((value | bitMask) == bitMask)); }
+template<typename Tv, typename Tm>
+bool mvkIsOnlyAnyFlagEnabled(Tv value, const Tm bitMask) { return (mvkIsAnyFlagEnabled(value, bitMask) && ((value | bitMask) == bitMask)); }
 
 /** Returns whether the specified value has ONLY ALL of the flags specified in bitMask enabled (set to 1), and none others. */
-template<typename T1, typename T2>
-bool mvkAreOnlyAllFlagsEnabled(T1 value, const T2 bitMask) { return (value == bitMask); }
+template<typename Tv, typename Tm>
+bool mvkAreOnlyAllFlagsEnabled(Tv value, const Tm bitMask) { return (value == bitMask); }