MVKCmdBlitImage support blit between different texture formats.

MVKRPSKeyBlitImg track both src and dst texture formats.
MVKCmdCopyImage fix copyable comparison.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index ad5a2a7..fbe04aa 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -72,7 +72,7 @@
 	_dstMTLPixFmt = _dstImage->getMTLPixelFormat();
 	_isDstCompressed = _dstImage->getIsCompressed();
 
-	_canCopyFormats = mvkMTLPixelFormatBytesPerBlock(_srcMTLPixFmt) == mvkMTLPixelFormatBytesPerBlock(_srcMTLPixFmt);
+	_canCopyFormats = mvkMTLPixelFormatBytesPerBlock(_srcMTLPixFmt) == mvkMTLPixelFormatBytesPerBlock(_dstMTLPixFmt);
 	_shouldUseTextureView = (_srcMTLPixFmt != _dstMTLPixFmt) && !(_isSrcCompressed || _isDstCompressed);	// Different formats and neither is compressed
 	_shouldUseTempBuffer = (_srcMTLPixFmt != _dstMTLPixFmt) && (_isSrcCompressed || _isDstCompressed);		// Different formats and at least one is compressed
 
@@ -216,16 +216,21 @@
 
 	_mtlFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
 
-	_blitKey.mtlPixFmt = (uint32_t)_dstMTLPixFmt;
-	_blitKey.mtlTexType = (uint32_t)_srcImage->getMTLTextureType();
+	_blitKey.srcMTLPixelFormat = (uint32_t)_srcMTLPixFmt;
+	_blitKey.srcMTLTextureType = (uint32_t)_srcImage->getMTLTextureType();
+	_blitKey.dstMTLPixelFormat = (uint32_t)_dstMTLPixFmt;
 
 	for (uint32_t i = 0; i < regionCount; i++) {
 		addImageBlitRegion(pRegions[i]);
 	}
 
 	// Validate
-	if ( !_mvkImageBlitRenders.empty() && (_blitKey.isDepthFormat() || _blitKey.isStencilFormat()) ) {
+	if ( !_mvkImageBlitRenders.empty() &&
+		(mvkMTLPixelFormatIsDepthFormat(_srcMTLPixFmt) ||
+		 mvkMTLPixelFormatIsStencilFormat(_srcMTLPixFmt)) ) {
+
 		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdBlitImage(): Scaling or inverting depth/stencil images is not supported."));
+		_mvkImageBlitRenders.clear();
 	}
 }
 
@@ -330,7 +335,7 @@
 	}
 
 	// Perform those BLITs that require rendering to destination texture.
-	if ( !_mvkImageBlitRenders.empty() && !(_blitKey.isDepthFormat() || _blitKey.isStencilFormat()) ) {
+	if ( !_mvkImageBlitRenders.empty() ) {
 
 		cmdEncoder->endCurrentMetalEncoding();
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index 5936b51..6a808be 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -35,32 +35,34 @@
  * This structure can be used as a key in a std::map and std::unordered_map.
  */
 typedef struct MVKRPSKeyBlitImg_t {
-	uint16_t mtlPixFmt = 0;			/**< MTLPixelFormat */
-	uint16_t mtlTexType = 0;		/**< MTLTextureType */
+	uint16_t srcMTLPixelFormat = 0;			/**< as MTLPixelFormat */
+	uint16_t srcMTLTextureType = 0;			/**< as MTLTextureType */
+	uint16_t dstMTLPixelFormat = 0;			/**< as MTLPixelFormat */
 
 	bool operator==(const MVKRPSKeyBlitImg_t& rhs) const {
-		return ((mtlPixFmt == rhs.mtlPixFmt) && (mtlTexType == rhs.mtlTexType));
+		if (srcMTLPixelFormat != rhs.srcMTLPixelFormat) { return false; }
+		if (srcMTLTextureType != rhs.srcMTLTextureType) { return false; }
+		if (dstMTLPixelFormat != rhs.dstMTLPixelFormat) { return false; }
+		return true;
 	}
 
-	inline MTLPixelFormat getMTLPixelFormat() { return (MTLPixelFormat)mtlPixFmt; }
+	inline MTLPixelFormat getSrcMTLPixelFormat() { return (MTLPixelFormat)srcMTLPixelFormat; }
 
-	inline bool isDepthFormat() { return mvkMTLPixelFormatIsDepthFormat(getMTLPixelFormat()); }
+	inline MTLPixelFormat getDstMTLPixelFormat() { return (MTLPixelFormat)dstMTLPixelFormat; }
 
-	inline bool isStencilFormat() { return mvkMTLPixelFormatIsStencilFormat(getMTLPixelFormat()); }
-
-	inline MTLTextureType getMTLTextureType() { return (MTLTextureType)mtlTexType; }
-
-	inline bool isArrayType() {
-		return (mtlTexType == MTLTextureType2DArray ||
+	inline bool isSrcArrayType() {
+		return (srcMTLTextureType == MTLTextureType2DArray ||
 #if MVK_MACOS
-				mtlTexType == MTLTextureType2DMultisampleArray ||
+				srcMTLTextureType == MTLTextureType2DMultisampleArray ||
 #endif
-				mtlTexType == MTLTextureType1DArray); }
+				srcMTLTextureType == MTLTextureType1DArray); }
 
 	std::size_t hash() const {
-		std::size_t hash = mtlTexType;
+		std::size_t hash = srcMTLPixelFormat;
 		hash <<= 16;
-		hash |= mtlPixFmt;
+		hash |= srcMTLTextureType;
+		hash <<= 16;
+		hash |= dstMTLPixelFormat;
 		return hash;
 	}
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index f4b6760..845450a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -39,7 +39,7 @@
 	plDesc.vertexFunction = getFunctionNamed("vtxCmdBlitImage");
     plDesc.fragmentFunction = getBlitFragFunction(blitKey);
 
-	plDesc.colorAttachments[0].pixelFormat = blitKey.getMTLPixelFormat();
+	plDesc.colorAttachments[0].pixelFormat = blitKey.getDstMTLPixelFormat();
 
     MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor;
 
@@ -132,9 +132,9 @@
 id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg& blitKey) {
 	id<MTLFunction> mtlFunc = nil;
 
-	NSString* typeStr = getMTLFormatTypeString(blitKey.getMTLPixelFormat());
+	NSString* typeStr = getMTLFormatTypeString(blitKey.getSrcMTLPixelFormat());
 
-	bool isArrayType = blitKey.isArrayType();
+	bool isArrayType = blitKey.isSrcArrayType();
 	NSString* arraySuffix = isArrayType ? @"_array" : @"";
 	NSString* sliceArg = isArrayType ? @", srcSlice" : @"";