From fa862c46a3c2f0db59bc00d19efbf8fa89313908 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 12 Sep 2020 15:55:41 -0500 Subject: [PATCH] MVKCmdCopyImage: Support copies between 3D and 2D images. This can be done by copying between each slice of the 2D image and each plane of the 3D image individually. This was actually quite simple to implement. I don't know why I punted on this. --- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 70 ++++++++++++++------ 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 5714c1b1..e4e641db 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -77,11 +77,6 @@ VkResult MVKCmdCopyImage::setContent(MVKCommandBuffer* cmdBuff, _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 @@ void MVKCmdCopyImage::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse com // 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)]; + } } } }