Merge pull request #1034 from cdavis5e/sampler-desc-autorelease

MVKSampler: Wrap MTLSamplerState creation in an autorelease pool.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 5714c1b..e4e641d 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -77,11 +77,6 @@
 		_vkImageCopies.push_back(vkIR);
 	}
     
-    // Validate
-    if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
-        return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Metal does not support copying to or from slices of a 3D texture.");
-    }
-
 	return VK_SUCCESS;
 }
 
@@ -160,25 +155,62 @@
             // 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 = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
-                                              srcOrigin,
-                                              mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
+            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;
             uint32_t dstBaseLayer = vkIC.dstSubresource.baseArrayLayer;
-            uint32_t layCnt = vkIC.srcSubresource.layerCount;
-
+            
             for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
-                [mtlBlitEnc copyFromTexture: srcMTLTex
-                                sourceSlice: srcBaseLayer + layIdx
-                                sourceLevel: srcLevel
-                               sourceOrigin: srcOrigin
-                                 sourceSize: srcSize
-                                  toTexture: dstMTLTex
-                           destinationSlice: dstBaseLayer + layIdx
-                           destinationLevel: dstLevel
-                          destinationOrigin: dstOrigin];
+                // 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)];
+                }
             }
         }
     }
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
index fb20ebf..7e8d55a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
@@ -59,7 +59,10 @@
 
 		// Command buffers start out in a VK_NOT_READY config result
 		VkResult cbRslt = mvkCmdBuff->getConfigurationResult();
-		if (rslt == VK_SUCCESS && cbRslt != VK_NOT_READY) { rslt = cbRslt; }
+		if (cbRslt != VK_NOT_READY) {
+			if (rslt == VK_SUCCESS) { rslt = cbRslt; }
+			freeCommandBuffers(1, &pCmdBuffer[cbIdx]);
+		}
 	}
 	return rslt;
 }
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index f0e1824..1fecb88 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -174,6 +174,7 @@
 	MVKInstance* mvkInst = new MVKInstance(pCreateInfo);
 	*pInstance = mvkInst->getVkInstance();
 	VkResult rslt = mvkInst->getConfigurationResult();
+	if (rslt < 0) { *pInstance = nullptr; mvkInst->destroy(); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -313,6 +314,7 @@
 	MVKDevice* mvkDev = new MVKDevice(mvkPD, pCreateInfo);
 	*pDevice = mvkDev->getVkDevice();
 	VkResult rslt = mvkDev->getConfigurationResult();
+	if (rslt < 0) { *pDevice = nullptr; mvkDev->destroy(); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -428,6 +430,7 @@
 	MVKDeviceMemory* mvkMem = mvkDev->allocateMemory(pAllocateInfo, pAllocator);
 	VkResult rslt = mvkMem->getConfigurationResult();
 	*pMem = (VkDeviceMemory)((rslt == VK_SUCCESS) ? mvkMem : VK_NULL_HANDLE);
+    if (rslt != VK_SUCCESS) { mvkDev->freeMemory(mvkMem, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -618,6 +621,7 @@
 	MVKFence* mvkFence = mvkDev->createFence(pCreateInfo, pAllocator);
 	*pFence = (VkFence)mvkFence;
 	VkResult rslt = mvkFence->getConfigurationResult();
+	if (rslt < 0) { *pFence = VK_NULL_HANDLE; mvkDev->destroyFence(mvkFence, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -680,6 +684,7 @@
 	MVKSemaphore* mvkSem4 = mvkDev->createSemaphore(pCreateInfo, pAllocator);
 	*pSemaphore = (VkSemaphore)mvkSem4;
 	VkResult rslt = mvkSem4->getConfigurationResult();
+	if (rslt < 0) { *pSemaphore = VK_NULL_HANDLE; mvkDev->destroySemaphore(mvkSem4, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -706,6 +711,7 @@
 	MVKEvent* mvkEvent = mvkDev->createEvent(pCreateInfo, pAllocator);
 	*pEvent = (VkEvent)mvkEvent;
 	VkResult rslt = mvkEvent->getConfigurationResult();
+	if (rslt < 0) { *pEvent = VK_NULL_HANDLE; mvkDev->destroyEvent(mvkEvent, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -765,6 +771,7 @@
 	MVKQueryPool* mvkQP = mvkDev->createQueryPool(pCreateInfo, pAllocator);
 	*pQueryPool = (VkQueryPool)mvkQP;
 	VkResult rslt = mvkQP->getConfigurationResult();
+	if (rslt < 0) { *pQueryPool = VK_NULL_HANDLE; mvkDev->destroyQueryPool(mvkQP, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -808,6 +815,7 @@
 	MVKBuffer* mvkBuff = mvkDev->createBuffer(pCreateInfo, pAllocator);
 	*pBuffer = (VkBuffer)mvkBuff;
 	VkResult rslt = mvkBuff->getConfigurationResult();
+	if (rslt < 0) { *pBuffer = VK_NULL_HANDLE; mvkDev->destroyBuffer(mvkBuff, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -834,6 +842,7 @@
     MVKBufferView* mvkBuffView = mvkDev->createBufferView(pCreateInfo, pAllocator);
     *pView = (VkBufferView)mvkBuffView;
     VkResult rslt = mvkBuffView->getConfigurationResult();
+	if (rslt < 0) { *pView = VK_NULL_HANDLE; mvkDev->destroyBufferView(mvkBuffView, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -860,6 +869,7 @@
 	MVKImage* mvkImg = mvkDev->createImage(pCreateInfo, pAllocator);
 	*pImage = (VkImage)mvkImg;
 	VkResult rslt = mvkImg->getConfigurationResult();
+	if (rslt < 0) { *pImage = VK_NULL_HANDLE; mvkDev->destroyImage(mvkImg, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -898,6 +908,7 @@
 	MVKImageView* mvkImgView = mvkDev->createImageView(pCreateInfo, pAllocator);
 	*pView = (VkImageView)mvkImgView;
 	VkResult rslt = mvkImgView->getConfigurationResult();
+	if (rslt < 0) { *pView = VK_NULL_HANDLE; mvkDev->destroyImageView(mvkImgView, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -924,6 +935,7 @@
 	MVKShaderModule* mvkShdrMod = mvkDev->createShaderModule(pCreateInfo, pAllocator);
 	*pShaderModule = (VkShaderModule)mvkShdrMod;
 	VkResult rslt = mvkShdrMod->getConfigurationResult();
+	if (rslt < 0) { *pShaderModule = VK_NULL_HANDLE; mvkDev->destroyShaderModule(mvkShdrMod, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -950,6 +962,7 @@
 	MVKPipelineCache* mvkPLC = mvkDev->createPipelineCache(pCreateInfo, pAllocator);
 	*pPipelineCache = (VkPipelineCache)mvkPLC;
 	VkResult rslt = mvkPLC->getConfigurationResult();
+	if (rslt < 0) { *pPipelineCache = VK_NULL_HANDLE; mvkDev->destroyPipelineCache(mvkPLC, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1043,6 +1056,7 @@
 	MVKPipelineLayout* mvkPLL = mvkDev->createPipelineLayout(pCreateInfo, pAllocator);
 	*pPipelineLayout = (VkPipelineLayout)mvkPLL;
 	VkResult rslt = mvkPLL->getConfigurationResult();
+	if (rslt < 0) { *pPipelineLayout = VK_NULL_HANDLE; mvkDev->destroyPipelineLayout(mvkPLL, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1069,6 +1083,7 @@
 	MVKSampler* mvkSamp = mvkDev->createSampler(pCreateInfo, pAllocator);
 	*pSampler = (VkSampler)mvkSamp;
 	VkResult rslt = mvkSamp->getConfigurationResult();
+	if (rslt < 0) { *pSampler = VK_NULL_HANDLE; mvkDev->destroySampler(mvkSamp, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1095,6 +1110,7 @@
 	MVKDescriptorSetLayout* mvkDSL = mvkDev->createDescriptorSetLayout(pCreateInfo, pAllocator);
 	*pSetLayout = (VkDescriptorSetLayout)mvkDSL;
 	VkResult rslt = mvkDSL->getConfigurationResult();
+	if (rslt < 0) { *pSetLayout = VK_NULL_HANDLE; mvkDev->destroyDescriptorSetLayout(mvkDSL, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1121,6 +1137,7 @@
 	MVKDescriptorPool* mvkDP = mvkDev->createDescriptorPool(pCreateInfo, pAllocator);
 	*pDescriptorPool = (VkDescriptorPool)mvkDP;
 	VkResult rslt = mvkDP->getConfigurationResult();
+	if (rslt < 0) { *pDescriptorPool = VK_NULL_HANDLE; mvkDev->destroyDescriptorPool(mvkDP, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1198,6 +1215,7 @@
 	MVKFramebuffer* mvkFB = mvkDev->createFramebuffer(pCreateInfo, pAllocator);
 	*pFramebuffer = (VkFramebuffer)mvkFB;
 	VkResult rslt = mvkFB->getConfigurationResult();
+	if (rslt < 0) { *pFramebuffer = VK_NULL_HANDLE; mvkDev->destroyFramebuffer(mvkFB, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1224,6 +1242,7 @@
 	MVKRenderPass* mvkRendPass = mvkDev->createRenderPass(pCreateInfo, pAllocator);
 	*pRenderPass = (VkRenderPass)mvkRendPass;
 	VkResult rslt = mvkRendPass->getConfigurationResult();
+	if (rslt < 0) { *pRenderPass = VK_NULL_HANDLE; mvkDev->destroyRenderPass(mvkRendPass, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -1261,6 +1280,7 @@
 	MVKCommandPool* mvkCmdPool = mvkDev->createCommandPool(pCreateInfo, pAllocator);
 	*pCmdPool = (VkCommandPool)mvkCmdPool;
 	VkResult rslt = mvkCmdPool->getConfigurationResult();
+	if (rslt < 0) { *pCmdPool = VK_NULL_HANDLE; mvkDev->destroyCommandPool(mvkCmdPool, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2146,6 +2166,10 @@
                                                           pAllocator);
     *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplate)mvkDUT;
     VkResult rslt = mvkDUT->getConfigurationResult();
+    if (rslt < 0) {
+        *pDescriptorUpdateTemplate = VK_NULL_HANDLE;
+        mvkDev->destroyDescriptorUpdateTemplate(mvkDUT, pAllocator);
+    }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2194,6 +2218,10 @@
 	MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
 	*pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
 	VkResult rslt = mvkSampConv->getConfigurationResult();
+    if (rslt < 0) {
+        *pYcbcrConversion = VK_NULL_HANDLE;
+        mvkDev->destroySamplerYcbcrConversion(mvkSampConv, pAllocator);
+    }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2267,6 +2295,7 @@
 	MVKRenderPass* mvkRendPass = mvkDev->createRenderPass(pCreateInfo, pAllocator);
 	*pRenderPass = (VkRenderPass)mvkRendPass;
 	VkResult rslt = mvkRendPass->getConfigurationResult();
+    if (rslt < 0) { *pRenderPass = VK_NULL_HANDLE; mvkDev->destroyRenderPass(mvkRendPass, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2423,6 +2452,7 @@
     MVKSwapchain* mvkSwpChn = mvkDev->createSwapchain(pCreateInfo, pAllocator);
     *pSwapchain = (VkSwapchainKHR)(mvkSwpChn);
     VkResult rslt = mvkSwpChn->getConfigurationResult();
+    if (rslt < 0) { *pSwapchain = VK_NULL_HANDLE; mvkDev->destroySwapchain(mvkSwpChn, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2647,6 +2677,7 @@
 	MVKDebugReportCallback* mvkDRCB = mvkInst->createDebugReportCallback(pCreateInfo, pAllocator);
 	*pCallback = (VkDebugReportCallbackEXT)mvkDRCB;
 	VkResult rslt = mvkDRCB->getConfigurationResult();
+    if (rslt < 0) { *pCallback = VK_NULL_HANDLE; mvkInst->destroyDebugReportCallback(mvkDRCB, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2814,6 +2845,7 @@
 	MVKDebugUtilsMessenger* mvkDUM = mvkInst->createDebugUtilsMessenger(pCreateInfo, pAllocator);
 	*pMessenger = (VkDebugUtilsMessengerEXT)mvkDUM;
 	VkResult rslt = mvkDUM->getConfigurationResult();
+    if (rslt < 0) { *pMessenger = VK_NULL_HANDLE; mvkInst->destroyDebugUtilsMessenger(mvkDUM, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2890,6 +2922,7 @@
 	MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator);
 	*pSurface = (VkSurfaceKHR)mvkSrfc;
 	VkResult rslt = mvkSrfc->getConfigurationResult();
+    if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -2934,6 +2967,7 @@
     MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator);
     *pSurface = (VkSurfaceKHR)mvkSrfc;
     VkResult rslt = mvkSrfc->getConfigurationResult();
+    if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); }
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }