Merge pull request #1067 from billhollings/setmtltex

vkSetMTLTextureMVK() Fix crash if incoming MTLTexture does not have an IOSurface.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 2873a8e..60c62d0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -154,62 +154,78 @@
 
             // If copies can be performed using direct texture-texture copying, do so
             uint32_t srcLevel = vkIC.srcSubresource.mipLevel;
-            MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(vkIC.srcOffset);
-            MTLSize srcSize;
-            uint32_t layCnt;
-            if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
-                // In the case, the number of layers to copy is in extent.depth. Use that value,
-                // then clamp the depth so we don't try to copy more than Metal will allow.
-                layCnt = vkIC.extent.depth;
-                srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
-                                          srcOrigin,
-                                          mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
-                srcSize.depth = 1;
-            } else {
-                layCnt = vkIC.srcSubresource.layerCount;
-                srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
-                                          srcOrigin,
-                                          mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
-            }
-            uint32_t dstLevel = vkIC.dstSubresource.mipLevel;
-            MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(vkIC.dstOffset);
             uint32_t srcBaseLayer = vkIC.srcSubresource.baseArrayLayer;
+            VkExtent3D srcExtent = _srcImage->getExtent3D(srcPlaneIndex, srcLevel);
+            uint32_t dstLevel = vkIC.dstSubresource.mipLevel;
             uint32_t dstBaseLayer = vkIC.dstSubresource.baseArrayLayer;
-            
-            for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
-                // We can copy between a 3D and a 2D image easily. Just copy between
-                // one slice of the 2D image and one plane of the 3D image at a time.
-                if ((_srcImage->getMTLTextureType() == MTLTextureType3D) == (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
-                    [mtlBlitEnc copyFromTexture: srcMTLTex
-                                    sourceSlice: srcBaseLayer + layIdx
-                                    sourceLevel: srcLevel
-                                   sourceOrigin: srcOrigin
-                                     sourceSize: srcSize
-                                      toTexture: dstMTLTex
-                               destinationSlice: dstBaseLayer + layIdx
-                               destinationLevel: dstLevel
-                              destinationOrigin: dstOrigin];
-                } else if (_srcImage->getMTLTextureType() == MTLTextureType3D) {
-                    [mtlBlitEnc copyFromTexture: srcMTLTex
-                                    sourceSlice: srcBaseLayer
-                                    sourceLevel: srcLevel
-                                   sourceOrigin: MTLOriginMake(srcOrigin.x, srcOrigin.y, srcOrigin.z + layIdx)
-                                     sourceSize: srcSize
-                                      toTexture: dstMTLTex
-                               destinationSlice: dstBaseLayer + layIdx
-                               destinationLevel: dstLevel
-                              destinationOrigin: dstOrigin];
+            VkExtent3D dstExtent = _dstImage->getExtent3D(srcPlaneIndex, srcLevel);
+            // If the extent completely covers both images, I can copy all layers at once.
+            // This will obviously not apply to copies between a 3D and 2D image.
+            if (mvkVkExtent3DsAreEqual(srcExtent, vkIC.extent) && mvkVkExtent3DsAreEqual(dstExtent, vkIC.extent)) {
+                assert((_srcImage->getMTLTextureType() == MTLTextureType3D) == (_dstImage->getMTLTextureType() == MTLTextureType3D));
+                [mtlBlitEnc copyFromTexture: srcMTLTex
+                                sourceSlice: srcBaseLayer
+                                sourceLevel: srcLevel
+                                  toTexture: dstMTLTex
+                           destinationSlice: dstBaseLayer
+                           destinationLevel: dstLevel
+                                 sliceCount: vkIC.srcSubresource.layerCount
+                                 levelCount: 1];
+            } else {
+                MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(vkIC.srcOffset);
+                MTLSize srcSize;
+                uint32_t layCnt;
+                if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
+                    // In the case, the number of layers to copy is in extent.depth. Use that value,
+                    // then clamp the depth so we don't try to copy more than Metal will allow.
+                    layCnt = vkIC.extent.depth;
+                    srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
+                                              srcOrigin,
+                                              mvkMTLSizeFromVkExtent3D(srcExtent));
+                    srcSize.depth = 1;
                 } else {
-                    assert(_dstImage->getMTLTextureType() == MTLTextureType3D);
-                    [mtlBlitEnc copyFromTexture: srcMTLTex
-                                    sourceSlice: srcBaseLayer + layIdx
-                                    sourceLevel: srcLevel
-                                   sourceOrigin: srcOrigin
-                                     sourceSize: srcSize
-                                      toTexture: dstMTLTex
-                               destinationSlice: dstBaseLayer
-                               destinationLevel: dstLevel
-                              destinationOrigin: MTLOriginMake(dstOrigin.x, dstOrigin.y, dstOrigin.z + layIdx)];
+                    layCnt = vkIC.srcSubresource.layerCount;
+                    srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
+                                              srcOrigin,
+                                              mvkMTLSizeFromVkExtent3D(srcExtent));
+                }
+                MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(vkIC.dstOffset);
+                
+                for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
+                    // We can copy between a 3D and a 2D image easily. Just copy between
+                    // one slice of the 2D image and one plane of the 3D image at a time.
+                    if ((_srcImage->getMTLTextureType() == MTLTextureType3D) == (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
+                        [mtlBlitEnc copyFromTexture: srcMTLTex
+                                        sourceSlice: srcBaseLayer + layIdx
+                                        sourceLevel: srcLevel
+                                       sourceOrigin: srcOrigin
+                                         sourceSize: srcSize
+                                          toTexture: dstMTLTex
+                                   destinationSlice: dstBaseLayer + layIdx
+                                   destinationLevel: dstLevel
+                                  destinationOrigin: dstOrigin];
+                    } else if (_srcImage->getMTLTextureType() == MTLTextureType3D) {
+                        [mtlBlitEnc copyFromTexture: srcMTLTex
+                                        sourceSlice: srcBaseLayer
+                                        sourceLevel: srcLevel
+                                       sourceOrigin: MTLOriginMake(srcOrigin.x, srcOrigin.y, srcOrigin.z + layIdx)
+                                         sourceSize: srcSize
+                                          toTexture: dstMTLTex
+                                   destinationSlice: dstBaseLayer + layIdx
+                                   destinationLevel: dstLevel
+                                  destinationOrigin: dstOrigin];
+                    } else {
+                        assert(_dstImage->getMTLTextureType() == MTLTextureType3D);
+                        [mtlBlitEnc copyFromTexture: srcMTLTex
+                                        sourceSlice: srcBaseLayer + layIdx
+                                        sourceLevel: srcLevel
+                                       sourceOrigin: srcOrigin
+                                         sourceSize: srcSize
+                                          toTexture: dstMTLTex
+                                   destinationSlice: dstBaseLayer
+                                   destinationLevel: dstLevel
+                                  destinationOrigin: MTLOriginMake(dstOrigin.x, dstOrigin.y, dstOrigin.z + layIdx)];
+                    }
                 }
             }
         }
@@ -1151,8 +1167,8 @@
 		VkRect2D renderArea = cmdEncoder->clipToRenderArea({{0, 0}, fbExtent});
 		fbExtent = {renderArea.offset.x + renderArea.extent.width, renderArea.offset.y + renderArea.extent.height};
 	}
-#endif
 	[tempRPDesc release];													// temp release
+#endif
 	populateVertices(cmdEncoder, vertices, fbExtent.width, fbExtent.height);
 
 	MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();