Merge pull request #1029 from cdavis5e/resolve-subregion-fix
MVKCmdResolveImage: Fix resolving sub-regions.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 4bc8b11..849d51c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -125,9 +125,8 @@
/** Describes Metal texture resolve parameters. */
typedef struct {
- VkImageCopy* copyRegion;
- uint32_t level;
- uint32_t slice;
+ VkImageSubresource srcSubresource;
+ VkImageSubresource dstSubresource;
} MVKMetalResolveSlice;
/**
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index f494748..24e840b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -490,68 +490,75 @@
uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.srcSubresource.aspectMask);
uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.dstSubresource.aspectMask);
- uint32_t mipLvl = vkIR.dstSubresource.mipLevel;
- VkExtent3D srcImgExt = _srcImage->getExtent3D(srcPlaneIndex, mipLvl);
- VkExtent3D dstImgExt = _dstImage->getExtent3D(dstPlaneIndex, mipLvl);
+ VkExtent3D srcImgExt = _srcImage->getExtent3D(srcPlaneIndex, vkIR.srcSubresource.mipLevel);
+ VkExtent3D dstImgExt = _dstImage->getExtent3D(dstPlaneIndex, vkIR.dstSubresource.mipLevel);
- // If the region does not cover the entire content of the source level, expand the
- // destination content in the region to the temporary image. The purpose of this
+ // If the region does not cover the entire content of the destination level, expand
+ // the destination content in the region to the temporary image. The purpose of this
// expansion is to render the existing content of the destination image to the
// temporary transfer multisample image, so that regions of that temporary transfer
// image can then be overwritten with content from the source image, prior to
- // resolving it back to the destination image. The source of this temporary content
- // move is the full extent of the DESTINATION image of the resolve command, and the
- // destination of this temporary content move is the full extent of the SOURCE image.
- if ( !mvkVkExtent3DsAreEqual(srcImgExt, vkIR.extent) ) {
+ // resolving it back to the destination image.
+ if ( !mvkVkExtent3DsAreEqual(dstImgExt, vkIR.extent) ) {
VkImageBlit& expRgn = expansionRegions[expCnt++];
expRgn.srcSubresource = vkIR.dstSubresource;
expRgn.srcOffsets[0] = { 0, 0, 0 };
expRgn.srcOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) };
expRgn.dstSubresource = vkIR.dstSubresource;
expRgn.dstOffsets[0] = { 0, 0, 0 };
- expRgn.dstOffsets[1] = { int32_t(srcImgExt.width), int32_t(srcImgExt.height), int32_t(srcImgExt.depth) };
+ expRgn.dstOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) };
}
// Copy the region from the source image to the temporary multisample image,
// prior to the temporary image being resolved back to the destination image.
// The source of this copy stage is the source image, and the destination of
// this copy stage is the temporary transfer image.
- VkImageCopy& cpyRgn = copyRegions[copyCnt++];
- cpyRgn.srcSubresource = vkIR.srcSubresource;
- cpyRgn.srcOffset = vkIR.srcOffset;
- cpyRgn.dstSubresource = vkIR.srcSubresource;
- cpyRgn.dstOffset = vkIR.srcOffset;
- cpyRgn.extent = vkIR.extent;
+ bool needXfrImage = !mvkVkExtent3DsAreEqual(srcImgExt, vkIR.extent) || !mvkVkExtent3DsAreEqual(dstImgExt, vkIR.extent);
+ if ( needXfrImage ) {
+ VkImageCopy& cpyRgn = copyRegions[copyCnt++];
+ cpyRgn.srcSubresource = vkIR.srcSubresource;
+ cpyRgn.srcOffset = vkIR.srcOffset;
+ cpyRgn.dstSubresource = vkIR.dstSubresource;
+ cpyRgn.dstOffset = vkIR.dstOffset;
+ cpyRgn.extent = vkIR.extent;
+ }
// Adds a resolve slice struct for each destination layer in the resolve region.
- uint32_t baseLayer = vkIR.dstSubresource.baseArrayLayer;
+ // Note that the source subresource for this is that of the SOURCE image if we're doing a
+ // direct resolve, but that of the DESTINATION if we need a temporary transfer image.
uint32_t layCnt = vkIR.dstSubresource.layerCount;
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sliceCnt++];
- rslvSlice.copyRegion = &cpyRgn;
- rslvSlice.level = vkIR.dstSubresource.mipLevel;
- rslvSlice.slice = baseLayer + layIdx;
+ rslvSlice.dstSubresource.aspectMask = vkIR.dstSubresource.aspectMask;
+ rslvSlice.dstSubresource.mipLevel = vkIR.dstSubresource.mipLevel;
+ rslvSlice.dstSubresource.arrayLayer = vkIR.dstSubresource.baseArrayLayer + layIdx;
+ rslvSlice.srcSubresource.aspectMask = needXfrImage ? vkIR.dstSubresource.aspectMask : vkIR.srcSubresource.aspectMask;
+ rslvSlice.srcSubresource.mipLevel = needXfrImage ? vkIR.dstSubresource.mipLevel : vkIR.srcSubresource.mipLevel;
+ rslvSlice.srcSubresource.arrayLayer = needXfrImage ? vkIR.dstSubresource.baseArrayLayer : vkIR.srcSubresource.baseArrayLayer;
+ rslvSlice.srcSubresource.arrayLayer += layIdx;
}
}
// Expansion and copying is not required. Each mip level of the source image
// is being resolved entirely. Resolve directly from the source image.
MVKImage* xfrImage = _srcImage;
- if (expCnt) {
- // Expansion and copying is required. Acquire a temporary transfer image, expand
- // the destination image into it, copy from the source image to the temporary image,
- // and then resolve from the temporary image to the destination image.
+ if (copyCnt) {
+ // Expansion and/or copying is required. Acquire a temporary transfer image, expand
+ // the destination image into it if necessary, copy from the source image to the
+ // temporary image, and then resolve from the temporary image to the destination image.
MVKImageDescriptorData xferImageData;
_dstImage->getTransferDescriptorData(xferImageData);
xferImageData.samples = _srcImage->getSampleCount();
xfrImage = cmdEncoder->getCommandEncodingPool()->getTransferMVKImage(xferImageData);
- // Expand the current content of the destination image to the temporary transfer image.
- MVKCmdBlitImage<N> expCmd;
- expCmd.setContent(cmdEncoder->_cmdBuffer,
- (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
- expCnt, expansionRegions, VK_FILTER_LINEAR);
- expCmd.encode(cmdEncoder, kMVKCommandUseResolveExpandImage);
+ if (expCnt) {
+ // Expand the current content of the destination image to the temporary transfer image.
+ MVKCmdBlitImage<N> expCmd;
+ expCmd.setContent(cmdEncoder->_cmdBuffer,
+ (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
+ expCnt, expansionRegions, VK_FILTER_LINEAR);
+ expCmd.encode(cmdEncoder, kMVKCommandUseResolveExpandImage);
+ }
// Copy the resolve regions of the source image to the temporary transfer image.
MVKCmdCopyImage<N> copyCmd;
@@ -573,15 +580,15 @@
// the texture level and slice and create a render encoder.
for (uint32_t sIdx = 0; sIdx < sliceCnt; sIdx++) {
MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sIdx];
- uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->srcSubresource.aspectMask);
- uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->dstSubresource.aspectMask);
+ uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.srcSubresource.aspectMask);
+ uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.dstSubresource.aspectMask);
mtlColorAttDesc.texture = xfrImage->getMTLTexture(srcPlaneIndex);
mtlColorAttDesc.resolveTexture = _dstImage->getMTLTexture(dstPlaneIndex);
- mtlColorAttDesc.level = rslvSlice.level;
- mtlColorAttDesc.slice = rslvSlice.slice;
- mtlColorAttDesc.resolveLevel = rslvSlice.level;
- mtlColorAttDesc.resolveSlice = rslvSlice.slice;
+ mtlColorAttDesc.level = rslvSlice.srcSubresource.mipLevel;
+ mtlColorAttDesc.slice = rslvSlice.srcSubresource.arrayLayer;
+ mtlColorAttDesc.resolveLevel = rslvSlice.dstSubresource.mipLevel;
+ mtlColorAttDesc.resolveSlice = rslvSlice.dstSubresource.arrayLayer;
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(kMVKCommandUseResolveImage));