Reduce memory requirements in MVKCmdTransfer.h/mm.
MVKCmdCopyImage, MVKCmdBlitImage, MVKCmdResolveImage generate derivative
arrays inline during encoding instead of holding as member variables.
Separate MVKCmdBlitImage from MVKCmdCopyImage and derive from MVKCommand instead.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 4b64184..9386582 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -54,29 +54,13 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- VkResult setContent(MVKCommandBuffer* cmdBuff,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- bool formatsMustMatch,
- MVKCommandUse commandUse);
- void addImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts);
- void addTempBufferImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts);
- MVKVectorInline<VkImageCopy, N> _imageCopyRegions;
- MVKVectorInline<VkBufferImageCopy, N> _srcTmpBuffImgCopies;
- MVKVectorInline<VkBufferImageCopy, N> _dstTmpBuffImgCopies;
- size_t _tmpBuffSize;
+ MVKVectorInline<VkImageCopy, N> _vkImageCopies;
MVKImage* _srcImage;
MVKImage* _dstImage;
VkImageLayout _srcLayout;
VkImageLayout _dstLayout;
MVKCommandUse _commandUse;
- bool _isSrcCompressed;
- bool _isDstCompressed;
- bool _canCopyFormats;
- bool _useTempBuffer;
};
// Concrete template class implementations.
@@ -101,7 +85,7 @@
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
-class MVKCmdBlitImage : public MVKCmdCopyImage<N> {
+class MVKCmdBlitImage : public MVKCommand {
public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
@@ -116,21 +100,19 @@
void encode(MVKCommandEncoder* cmdEncoder) override;
- MVKCmdBlitImage();
-
- ~MVKCmdBlitImage() override;
-
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+ bool canCopyFormats();
bool canCopy(const VkImageBlit& region);
- void addImageBlitRegion(const VkImageBlit& region, MVKPixelFormats* pixFmts);
- void addImageCopyRegionFromBlitRegion(const VkImageBlit& region, MVKPixelFormats* pixFmts);
void populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region);
- void initMTLRenderPassDescriptor();
- MVKVectorInline<MVKImageBlitRender, N> _mvkImageBlitRenders;
- MVKRPSKeyBlitImg _blitKey;
- MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
+ MVKVectorInline<VkImageBlit, N> _vkImageBlits;
+ MVKImage* _srcImage;
+ MVKImage* _dstImage;
+ VkImageLayout _srcLayout;
+ VkImageLayout _dstLayout;
+ VkFilter _filter;
+ MVKCommandUse _commandUse;
};
// Concrete template class implementations.
@@ -165,22 +147,10 @@
void encode(MVKCommandEncoder* cmdEncoder) override;
- MVKCmdResolveImage();
-
- ~MVKCmdResolveImage() override;
-
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- void addExpansionRegion(const VkImageResolve& resolveRegion);
- void addCopyRegion(const VkImageResolve& resolveRegion);
- void addResolveSlices(const VkImageResolve& resolveRegion);
- void initMTLRenderPassDescriptor();
- MVKVectorInline<VkImageCopy, N> _copyRegions;
- MVKVectorInline<VkImageBlit, N> _expansionRegions;
- MVKVectorInline<MVKMetalResolveSlice, N> _mtlResolveSlices;
- MVKImageDescriptorData _transferImageData;
- MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
+ MVKVectorInline<VkImageResolve, N> _vkImageResolves;
MVKImage* _srcImage;
MVKImage* _dstImage;
VkImageLayout _srcLayout;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index b160c85..e9d5b15 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -56,17 +56,24 @@
uint32_t regionCount,
const VkImageCopy* pRegions,
MVKCommandUse commandUse) {
+ _srcImage = (MVKImage*)srcImage;
+ _srcLayout = srcImageLayout;
- setContent(cmdBuff, srcImage, srcImageLayout, dstImage, dstImageLayout, false, commandUse);
+ _dstImage = (MVKImage*)dstImage;
+ _dstLayout = dstImageLayout;
- MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
+ _commandUse = commandUse;
+
+ _vkImageCopies.clear(); // Clear for reuse
for (uint32_t i = 0; i < regionCount; i++) {
- addImageCopyRegion(pRegions[i], pixFmts);
+ _vkImageCopies.push_back(pRegions[i]);
}
// Validate
- if ( !_canCopyFormats ) {
- return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Cannot copy between incompatible formats, such as formats of different pixel sizes.");
+ MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
+ if ((_dstImage->getSampleCount() != _srcImage->getSampleCount()) ||
+ (pixFmts->getBytesPerBlock(_dstImage->getMTLPixelFormat()) != pixFmts->getBytesPerBlock(_srcImage->getMTLPixelFormat()))) {
+ return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Cannot copy between incompatible formats, such as formats of different pixel sizes, or between images with different sample counts.");
}
if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Metal does not support copying to or from slices of a 3D texture.");
@@ -75,165 +82,111 @@
return VK_SUCCESS;
}
-// Sets common content for use by this class and subclasses
-template <size_t N>
-VkResult MVKCmdCopyImage<N>::setContent(MVKCommandBuffer* cmdBuff,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- bool formatsMustMatch,
- MVKCommandUse commandUse) {
- MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
-
- _srcImage = (MVKImage*)srcImage;
- _srcLayout = srcImageLayout;
- _isSrcCompressed = _srcImage->getIsCompressed();
- MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
- uint32_t srcSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_srcImage->getSampleCount());
- uint32_t srcBytesPerBlock = pixFmts->getBytesPerBlock(srcMTLPixFmt);
-
- _dstImage = (MVKImage*)dstImage;
- _dstLayout = dstImageLayout;
- _isDstCompressed = _dstImage->getIsCompressed();
- MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat();
- uint32_t dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
- uint32_t dstBytesPerBlock = pixFmts->getBytesPerBlock(dstMTLPixFmt);
-
- _canCopyFormats = (dstSampleCount == srcSampleCount) && (formatsMustMatch
- ? (dstMTLPixFmt == srcMTLPixFmt)
- : (dstBytesPerBlock == srcBytesPerBlock));
-
- _useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (_isSrcCompressed || _isDstCompressed); // Different formats and at least one is compressed
-
- _commandUse = commandUse;
- _tmpBuffSize = 0;
-
- _imageCopyRegions.clear(); // Clear for reuse
- _srcTmpBuffImgCopies.clear(); // Clear for reuse
- _dstTmpBuffImgCopies.clear(); // Clear for reuse
-
- return VK_SUCCESS;
-}
-
-template <size_t N>
-void MVKCmdCopyImage<N>::addImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts) {
- if (_useTempBuffer) {
- addTempBufferImageCopyRegion(region, pixFmts); // Convert to image->buffer->image copies
- } else {
- _imageCopyRegions.push_back(region);
- }
-}
-
-// Add an image->buffer copy and buffer->image copy to replace the image->image copy
-template <size_t N>
-void MVKCmdCopyImage<N>::addTempBufferImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts) {
-
- // Add copy from source image to temp buffer.
- VkBufferImageCopy buffImgCpy;
- buffImgCpy.bufferOffset = _tmpBuffSize;
- buffImgCpy.bufferRowLength = 0;
- buffImgCpy.bufferImageHeight = 0;
- buffImgCpy.imageSubresource = region.srcSubresource;
- buffImgCpy.imageOffset = region.srcOffset;
- buffImgCpy.imageExtent = region.extent;
- _srcTmpBuffImgCopies.push_back(buffImgCpy);
-
- // Add copy from temp buffer to destination image.
- // Extent is provided in source texels. If the source is compressed but the
- // destination is not, each destination pixel will consume an entire source block,
- // so we must downscale the destination extent by the size of the source block.
- MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
- VkExtent3D dstExtent = region.extent;
- if (_isSrcCompressed && !_isDstCompressed) {
- VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
- dstExtent.width /= srcBlockExtent.width;
- dstExtent.height /= srcBlockExtent.height;
- }
- buffImgCpy.bufferOffset = _tmpBuffSize;
- buffImgCpy.bufferRowLength = 0;
- buffImgCpy.bufferImageHeight = 0;
- buffImgCpy.imageSubresource = region.dstSubresource;
- buffImgCpy.imageOffset = region.dstOffset;
- buffImgCpy.imageExtent = dstExtent;
- _dstTmpBuffImgCopies.push_back(buffImgCpy);
-
- NSUInteger bytesPerRow = pixFmts->getBytesPerRow(srcMTLPixFmt, region.extent.width);
- NSUInteger bytesPerRegion = pixFmts->getBytesPerLayer(srcMTLPixFmt, bytesPerRow, region.extent.height);
- _tmpBuffSize += bytesPerRegion;
-}
-
template <size_t N>
void MVKCmdCopyImage<N>::encode(MVKCommandEncoder* cmdEncoder) {
- // Unless we need to use an intermediary buffer copy, map the source pixel format to the
- // dest pixel format through a texture view on the source texture. If the source and dest
- // pixel formats are the same, this will simply degenerate to the source texture itself.
- MTLPixelFormat mapSrcMTLPixFmt = (_useTempBuffer ? _srcImage : _dstImage)->getMTLPixelFormat();
- id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(mapSrcMTLPixFmt);
- id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
- if ( !srcMTLTex || !dstMTLTex ) { return; }
- id<MTLBlitCommandEncoder> mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(_commandUse);
+ MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
+ bool isSrcCompressed = _srcImage->getIsCompressed();
- // If copies can be performed using direct texture-texture copying, do so
- for (auto& cpyRgn : _imageCopyRegions) {
- uint32_t srcLevel = cpyRgn.srcSubresource.mipLevel;
- MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.srcOffset);
- MTLSize srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(cpyRgn.extent),
- srcOrigin,
- mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcLevel)));
- uint32_t dstLevel = cpyRgn.dstSubresource.mipLevel;
- MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.dstOffset);
- uint32_t srcBaseLayer = cpyRgn.srcSubresource.baseArrayLayer;
- uint32_t dstBaseLayer = cpyRgn.dstSubresource.baseArrayLayer;
- uint32_t layCnt = cpyRgn.srcSubresource.layerCount;
+ MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat();
+ bool isDstCompressed = _dstImage->getIsCompressed();
- 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];
+ // If source and destination have different formats and at least one is compressed, use a temporary intermediary buffer
+ bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isSrcCompressed || isDstCompressed);
+ if (useTempBuffer) {
+ MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
+ uint32_t copyCnt = (uint32_t)_vkImageCopies.size();
+ VkBufferImageCopy vkSrcCopies[copyCnt];
+ VkBufferImageCopy vkDstCopies[copyCnt];
+ size_t tmpBuffSize = 0;
+ for (uint32_t copyIdx = 0; copyIdx < copyCnt; copyIdx++) {
+ auto& vkIC = _vkImageCopies[copyIdx];
+
+ // Add copy from source image to temp buffer.
+ auto& srcCpy = vkSrcCopies[copyIdx];
+ srcCpy.bufferOffset = tmpBuffSize;
+ srcCpy.bufferRowLength = 0;
+ srcCpy.bufferImageHeight = 0;
+ srcCpy.imageSubresource = vkIC.srcSubresource;
+ srcCpy.imageOffset = vkIC.srcOffset;
+ srcCpy.imageExtent = vkIC.extent;
+
+ // Add copy from temp buffer to destination image.
+ // Extent is provided in source texels. If the source is compressed but the
+ // destination is not, each destination pixel will consume an entire source block,
+ // so we must downscale the destination extent by the size of the source block.
+ VkExtent3D dstExtent = vkIC.extent;
+ if (isSrcCompressed && !isDstCompressed) {
+ VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
+ dstExtent.width /= srcBlockExtent.width;
+ dstExtent.height /= srcBlockExtent.height;
+ }
+ auto& dstCpy = vkDstCopies[copyIdx];
+ dstCpy.bufferOffset = tmpBuffSize;
+ dstCpy.bufferRowLength = 0;
+ dstCpy.bufferImageHeight = 0;
+ dstCpy.imageSubresource = vkIC.dstSubresource;
+ dstCpy.imageOffset = vkIC.dstOffset;
+ dstCpy.imageExtent = dstExtent;
+
+ size_t bytesPerRow = pixFmts->getBytesPerRow(srcMTLPixFmt, vkIC.extent.width);
+ size_t bytesPerRegion = pixFmts->getBytesPerLayer(srcMTLPixFmt, bytesPerRow, vkIC.extent.height);
+ tmpBuffSize += bytesPerRegion;
}
- }
- // If copies could not be performed directly between images,
- // use a temporary buffer acting as a waystation between the images.
- if ( !_srcTmpBuffImgCopies.empty() ) {
MVKBufferDescriptorData tempBuffData;
- tempBuffData.size = _tmpBuffSize;
+ tempBuffData.size = tmpBuffSize;
tempBuffData.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- MVKBuffer* tempBuff = cmdEncoder->getCommandEncodingPool()->getTransferMVKBuffer(tempBuffData);
+ VkBuffer tempBuff = (VkBuffer)cmdEncoder->getCommandEncodingPool()->getTransferMVKBuffer(tempBuffData);
MVKCmdBufferImageCopy<N> cpyCmd;
// Copy from source image to buffer
// Create and execute a temporary buffer image command.
// To be threadsafe...do NOT acquire and return the command from the pool.
- cpyCmd.setContent(cmdEncoder->_cmdBuffer,
- (VkBuffer) tempBuff,
- (VkImage) _srcImage,
- _srcLayout,
- (uint32_t)_srcTmpBuffImgCopies.size(),
- _srcTmpBuffImgCopies.data(),
- false);
+ cpyCmd.setContent(cmdEncoder->_cmdBuffer, tempBuff, (VkImage)_srcImage, _srcLayout, copyCnt, vkSrcCopies, false);
cpyCmd.encode(cmdEncoder);
// Copy from buffer to destination image
// Create and execute a temporary buffer image command.
// To be threadsafe...do NOT acquire and return the command from the pool.
- cpyCmd.setContent(cmdEncoder->_cmdBuffer,
- (VkBuffer) tempBuff,
- (VkImage) _dstImage,
- _dstLayout,
- (uint32_t)_dstTmpBuffImgCopies.size(),
- _dstTmpBuffImgCopies.data(),
- true);
+ cpyCmd.setContent(cmdEncoder->_cmdBuffer, tempBuff, (VkImage)_dstImage, _dstLayout, copyCnt, vkDstCopies, true);
cpyCmd.encode(cmdEncoder);
+
+ } else {
+ // Map the source pixel format to the dest pixel format through a texture view on the source texture.
+ // If the source and dest pixel formats are the same, this will simply degenerate to the source texture itself.
+ id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(_dstImage->getMTLPixelFormat());
+ id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
+ if ( !srcMTLTex || !dstMTLTex ) { return; }
+
+ id<MTLBlitCommandEncoder> mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(_commandUse);
+
+ // If copies can be performed using direct texture-texture copying, do so
+ for (auto& cpyRgn : _vkImageCopies) {
+ uint32_t srcLevel = cpyRgn.srcSubresource.mipLevel;
+ MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.srcOffset);
+ MTLSize srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(cpyRgn.extent),
+ srcOrigin,
+ mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcLevel)));
+ uint32_t dstLevel = cpyRgn.dstSubresource.mipLevel;
+ MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.dstOffset);
+ uint32_t srcBaseLayer = cpyRgn.srcSubresource.baseArrayLayer;
+ uint32_t dstBaseLayer = cpyRgn.dstSubresource.baseArrayLayer;
+ uint32_t layCnt = cpyRgn.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];
+ }
+ }
}
}
@@ -255,47 +208,39 @@
VkFilter filter,
MVKCommandUse commandUse) {
- VkResult rslt = MVKCmdCopyImage<N>::setContent(cmdBuff, srcImage, srcImageLayout, dstImage, dstImageLayout, true, commandUse);
-
- MVKImage* srcImg = MVKCmdCopyImage<N>::_srcImage;
- MVKImage* dstImg = MVKCmdCopyImage<N>::_dstImage;
-
- _blitKey.srcMTLPixelFormat = srcImg->getMTLPixelFormat();
- _blitKey.srcMTLTextureType = srcImg->getMTLTextureType();
- _blitKey.dstMTLPixelFormat = dstImg->getMTLPixelFormat();
- _blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
- _blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(dstImg->getSampleCount());
-
MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
- _mvkImageBlitRenders.clear(); // Clear for reuse
+ _srcImage = (MVKImage*)srcImage;
+ _srcLayout = srcImageLayout;
+
+ _dstImage = (MVKImage*)dstImage;
+ _dstLayout = dstImageLayout;
+
+ _filter = filter;
+ _commandUse = commandUse;
+
+ _vkImageBlits.clear(); // Clear for reuse
for (uint32_t i = 0; i < regionCount; i++) {
- addImageBlitRegion(pRegions[i], pixFmts);
+ _vkImageBlits.push_back(pRegions[i]);
}
- // Validate
- MTLPixelFormat srcMTLPixFmt = srcImg->getMTLPixelFormat();
- if ( !_mvkImageBlitRenders.empty() &&
- (pixFmts->isDepthFormat(srcMTLPixFmt) || pixFmts->isStencilFormat(srcMTLPixFmt)) ) {
-
- _mvkImageBlitRenders.clear();
- return MVKCmdCopyImage<N>::reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdBlitImage(): Scaling or inverting depth/stencil images is not supported.");
+ // Validate - depth stencil formats cannot be scaled or inverted
+ MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
+ if (pixFmts->isDepthFormat(srcMTLPixFmt) || pixFmts->isStencilFormat(srcMTLPixFmt)) {
+ bool canCopyFmts = canCopyFormats();
+ for (auto& vkIB : _vkImageBlits) {
+ if ( !(canCopyFmts && canCopy(vkIB)) ) {
+ return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdBlitImage(): Scaling or inverting depth/stencil images is not supported.");
+ }
+ }
}
-
- return rslt;
+ return VK_SUCCESS;
}
template <size_t N>
-void MVKCmdBlitImage<N>::addImageBlitRegion(const VkImageBlit& region,
- MVKPixelFormats* pixFmts) {
- if (MVKCmdCopyImage<N>::_canCopyFormats && canCopy(region)) {
- addImageCopyRegionFromBlitRegion(region, pixFmts); // Convert to image copy
- } else {
- MVKImageBlitRender blitRender;
- blitRender.region = region;
- populateVertices(blitRender.vertices, region);
- _mvkImageBlitRenders.push_back(blitRender);
- }
+bool MVKCmdBlitImage<N>::canCopyFormats() {
+ return ((_srcImage->getMTLPixelFormat() == _dstImage->getMTLPixelFormat()) &&
+ (_dstImage->getSampleCount() == _srcImage->getSampleCount()));
}
// The source and destination sizes must be equal and not be negative in any direction
@@ -308,24 +253,6 @@
}
template <size_t N>
-void MVKCmdBlitImage<N>::addImageCopyRegionFromBlitRegion(const VkImageBlit& region,
- MVKPixelFormats* pixFmts) {
- const VkOffset3D& so0 = region.srcOffsets[0];
- const VkOffset3D& so1 = region.srcOffsets[1];
-
- VkImageCopy cpyRgn;
- cpyRgn.srcSubresource = region.srcSubresource;
- cpyRgn.srcOffset = region.srcOffsets[0];
- cpyRgn.dstSubresource = region.dstSubresource;
- cpyRgn.dstOffset = region.dstOffsets[0];
- cpyRgn.extent.width = so1.x - so0.x;
- cpyRgn.extent.height = so1.y - so0.y;
- cpyRgn.extent.depth = so1.z - so0.z;
-
- MVKCmdCopyImage<N>::addImageCopyRegion(cpyRgn, pixFmts);
-}
-
-template <size_t N>
void MVKCmdBlitImage<N>::populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region) {
const VkOffset3D& so0 = region.srcOffsets[0];
const VkOffset3D& so1 = region.srcOffsets[1];
@@ -333,8 +260,8 @@
const VkOffset3D& do1 = region.dstOffsets[1];
// Get the extents of the source and destination textures.
- VkExtent3D srcExtent = MVKCmdCopyImage<N>::_srcImage->getExtent3D(region.srcSubresource.mipLevel);
- VkExtent3D dstExtent = MVKCmdCopyImage<N>::_dstImage->getExtent3D(region.dstSubresource.mipLevel);
+ VkExtent3D srcExtent = _srcImage->getExtent3D(region.srcSubresource.mipLevel);
+ VkExtent3D dstExtent = _dstImage->getExtent3D(region.dstSubresource.mipLevel);
// Determine the bottom-left and top-right corners of the source and destination
// texture regions, each as a fraction of the corresponding texture size.
@@ -387,48 +314,93 @@
template <size_t N>
void MVKCmdBlitImage<N>::encode(MVKCommandEncoder* cmdEncoder) {
+ size_t vkIBCnt = _vkImageBlits.size();
+ VkImageCopy vkImageCopies[vkIBCnt];
+ MVKImageBlitRender mvkBlitRenders[vkIBCnt];
+ uint32_t copyCnt = 0;
+ uint32_t blitCnt = 0;
+
+ // Separate BLITs into those that are really just simple texure region copies,
+ // and those that require rendering
+ bool canCopyFmts = canCopyFormats();
+ for (auto& vkIB : _vkImageBlits) {
+ if (canCopyFmts && canCopy(vkIB)) {
+
+ const VkOffset3D& so0 = vkIB.srcOffsets[0];
+ const VkOffset3D& so1 = vkIB.srcOffsets[1];
+
+ auto& vkIC = vkImageCopies[copyCnt++];
+ vkIC.srcSubresource = vkIB.srcSubresource;
+ vkIC.srcOffset = vkIB.srcOffsets[0];
+ vkIC.dstSubresource = vkIB.dstSubresource;
+ vkIC.dstOffset = vkIB.dstOffsets[0];
+ vkIC.extent.width = so1.x - so0.x;
+ vkIC.extent.height = so1.y - so0.y;
+ vkIC.extent.depth = so1.z - so0.z;
+
+ } else {
+ auto& mvkIBR = mvkBlitRenders[blitCnt++];
+ mvkIBR.region = vkIB;
+ populateVertices(mvkIBR.vertices, vkIB);
+ }
+ }
+
// Perform those BLITs that can be covered by simple texture copying.
- if ( !MVKCmdCopyImage<N>::_imageCopyRegions.empty() ) {
- MVKCmdCopyImage<N>::encode(cmdEncoder);
+ if (copyCnt) {
+ MVKCmdCopyImage<N> copyCmd;
+ copyCmd.setContent(cmdEncoder->_cmdBuffer,
+ (VkImage)_srcImage, _srcLayout,
+ (VkImage)_dstImage, _dstLayout,
+ copyCnt, vkImageCopies, kMVKCommandUseBlitImage);
+ copyCmd.encode(cmdEncoder);
}
// Perform those BLITs that require rendering to destination texture.
- if ( !_mvkImageBlitRenders.empty() ) {
+ id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture();
+ id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
+ if (blitCnt && srcMTLTex && dstMTLTex) {
cmdEncoder->endCurrentMetalEncoding();
- id<MTLTexture> srcMTLTex = MVKCmdCopyImage<N>::_srcImage->getMTLTexture();
- id<MTLTexture> dstMTLTex = MVKCmdCopyImage<N>::_dstImage->getMTLTexture();
- if ( !srcMTLTex || !dstMTLTex ) { return; }
-
- MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
+ MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor];
+ MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPD.colorAttachments[0];
+ mtlColorAttDesc.loadAction = MTLLoadActionLoad;
+ mtlColorAttDesc.storeAction = MTLStoreActionStore;
mtlColorAttDesc.texture = dstMTLTex;
+ MVKRPSKeyBlitImg blitKey;
+ blitKey.srcMTLPixelFormat = _srcImage->getMTLPixelFormat();
+ blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
+ blitKey.dstMTLPixelFormat = _dstImage->getMTLPixelFormat();
+ blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter);
+ blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
+ id<MTLRenderPipelineState> mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(blitKey);
+
uint32_t vtxBuffIdx = cmdEncoder->getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
- id<MTLRenderPipelineState> mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(_blitKey);
- for (auto& bltRend : _mvkImageBlitRenders) {
+ for (uint32_t blitIdx = 0; blitIdx < blitCnt; blitIdx++) {
+ auto& mvkIBR = mvkBlitRenders[blitIdx];
- mtlColorAttDesc.level = bltRend.region.dstSubresource.mipLevel;
+ mtlColorAttDesc.level = mvkIBR.region.dstSubresource.mipLevel;
- uint32_t layCnt = bltRend.region.srcSubresource.layerCount;
+ uint32_t layCnt = mvkIBR.region.srcSubresource.layerCount;
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
// Update the render pass descriptor for the texture level and slice, and create a render encoder.
- mtlColorAttDesc.slice = bltRend.region.dstSubresource.baseArrayLayer + layIdx;
- id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: _mtlRenderPassDescriptor];
- setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(MVKCmdCopyImage<N>::_commandUse));
+ mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+ id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
+ setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(_commandUse));
[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
[mtlRendEnc setRenderPipelineState: mtlRPS];
- cmdEncoder->setVertexBytes(mtlRendEnc, bltRend.vertices, sizeof(bltRend.vertices), vtxBuffIdx);
+ cmdEncoder->setVertexBytes(mtlRendEnc, mvkIBR.vertices, sizeof(mvkIBR.vertices), vtxBuffIdx);
[mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0];
struct {
uint slice;
float lod;
} texSubRez;
- texSubRez.slice = bltRend.region.srcSubresource.baseArrayLayer + layIdx;
- texSubRez.lod = bltRend.region.srcSubresource.mipLevel;
+ texSubRez.slice = mvkIBR.region.srcSubresource.baseArrayLayer + layIdx;
+ texSubRez.lod = mvkIBR.region.srcSubresource.mipLevel;
cmdEncoder->setFragmentBytes(mtlRendEnc, &texSubRez, sizeof(texSubRez), 0);
[mtlRendEnc drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: kMVKBlitVertexCount];
@@ -439,28 +411,6 @@
}
}
-
-#pragma mark Construction
-
-template <size_t N>
-MVKCmdBlitImage<N>::MVKCmdBlitImage() {
- initMTLRenderPassDescriptor();
-}
-
-// Create and configure the render pass descriptor
-template <size_t N>
-void MVKCmdBlitImage<N>::initMTLRenderPassDescriptor() {
- _mtlRenderPassDescriptor = [[MTLRenderPassDescriptor renderPassDescriptor] retain]; // retained
- MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
- mtlColorAttDesc.loadAction = MTLLoadActionLoad;
- mtlColorAttDesc.storeAction = MTLStoreActionStore;
-}
-
-template <size_t N>
-MVKCmdBlitImage<N>::~MVKCmdBlitImage() {
- [_mtlRenderPassDescriptor release];
-}
-
template class MVKCmdBlitImage<1>;
template class MVKCmdBlitImage<4>;
@@ -481,183 +431,137 @@
_dstImage = (MVKImage*)dstImage;
_dstLayout = dstImageLayout;
- // Deterine the total number of texture layers being affected
- uint32_t layerCnt = 0;
+ _vkImageResolves.clear(); // Clear for reuse
+ _vkImageResolves.reserve(regionCount);
for (uint32_t i = 0; i < regionCount; i++) {
- layerCnt += pRegions[i].dstSubresource.layerCount;
+ _vkImageResolves.push_back(pRegions[i]);
}
- // Resize the region arrays accordingly
- _expansionRegions.clear(); // Clear for reuse
- _expansionRegions.reserve(regionCount);
- _copyRegions.clear(); // Clear for reuse
- _copyRegions.reserve(regionCount);
- _mtlResolveSlices.clear(); // Clear for reuse
- _mtlResolveSlices.reserve(layerCnt);
-
- // Add image regions
- for (uint32_t i = 0; i < regionCount; i++) {
- const VkImageResolve& rslvRgn = pRegions[i];
- addExpansionRegion(rslvRgn);
- addCopyRegion(rslvRgn);
- addResolveSlices(rslvRgn);
- }
-
- _dstImage->getTransferDescriptorData(_transferImageData);
- _transferImageData.samples = _srcImage->getSampleCount();
-
// Validate
- if ( !mvkAreAllFlagsEnabled(cmdBuff->getPixelFormats()->getCapabilities(_dstImage->getMTLPixelFormat()), kMVKMTLFmtCapsResolve) ) {
- return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", cmdBuff->getPixelFormats()->getName(_dstImage->getVkFormat()));
+ MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
+ if ( !mvkAreAllFlagsEnabled(pixFmts->getCapabilities(_dstImage->getMTLPixelFormat()), kMVKMTLFmtCapsResolve) ) {
+ return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", pixFmts->getName(_dstImage->getVkFormat()));
}
return VK_SUCCESS;
}
-// Adds a VkImageBlit region, constructed from the resolve region, to the internal collection
-// of expansion regions, unless the entire content of the destination texture of this command
-// is to be resolved, an expansion region will not be added.
-//
-// The purpose of an expansion regions is to render the existing content of the destination
-// image of this command to the temporary transfer multisample image, so that regions of that
-// temporary transfer image can then be overwritten with content from the source image of this
-// command, prior to resolving it back to the destination image of this command.
-//
-// As such, the source of this expansion stage is the destination image of this command,
-// and the destination of this expansion stage is a temp image that has the same shape
-// as the source image of this command.
-template <size_t N>
-void MVKCmdResolveImage<N>::addExpansionRegion(const VkImageResolve& resolveRegion) {
- uint32_t mipLvl = resolveRegion.dstSubresource.mipLevel;
- VkExtent3D srcImgExt = _srcImage->getExtent3D(mipLvl);
- VkExtent3D dstImgExt = _dstImage->getExtent3D(mipLvl);
-
- // No need to add an expansion region if the entire content of
- // the source image is being resolved to the destination image.
- if (mvkVkExtent3DsAreEqual(srcImgExt, resolveRegion.extent)) { return; }
-
- // 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 of the resolve command.
- VkImageBlit expRgn = {
- .srcSubresource = resolveRegion.dstSubresource,
- .srcOffsets[0] = { 0, 0, 0 },
- .srcOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) },
- .dstSubresource = resolveRegion.dstSubresource,
- .dstOffsets[0] = { 0, 0, 0 },
- .dstOffsets[1] = { int32_t(srcImgExt.width), int32_t(srcImgExt.height), int32_t(srcImgExt.depth) },
- };
- _expansionRegions.push_back(expRgn);
-}
-
-// Adds a VkImageCopy region, constructed from the resolve region,
-// to the internal collection of copy regions.
-//
-// The purpose of a copy region is to copy regions from the source image of this command to
-// the temporary image, prior to the temporary image being resolved back to the destination
-// image of this command.
-//
-// As such, the source of this copy stage is the source image of this command, and the
-// destination of this copy stage is the temporary transfer image that has the same shape
-// as the source image of this command.
-template <size_t N>
-void MVKCmdResolveImage<N>::addCopyRegion(const VkImageResolve& resolveRegion) {
- VkImageCopy cpyRgn = {
- .srcSubresource = resolveRegion.srcSubresource,
- .srcOffset = resolveRegion.srcOffset,
- .dstSubresource = resolveRegion.srcSubresource,
- .dstOffset = resolveRegion.srcOffset,
- .extent = resolveRegion.extent,
- };
- _copyRegions.push_back(cpyRgn);
-}
-
-// Adds a resolve slice struct for each destination layer in the resolve region.
-template <size_t N>
-void MVKCmdResolveImage<N>::addResolveSlices(const VkImageResolve& resolveRegion) {
- MVKMetalResolveSlice rslvSlice;
- rslvSlice.level = resolveRegion.dstSubresource.mipLevel;
-
- uint32_t baseLayer = resolveRegion.dstSubresource.baseArrayLayer;
- uint32_t layCnt = resolveRegion.dstSubresource.layerCount;
- for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
- rslvSlice.slice = baseLayer + layIdx;
- _mtlResolveSlices.push_back(rslvSlice);
- }
-}
-
template <size_t N>
void MVKCmdResolveImage<N>::encode(MVKCommandEncoder* cmdEncoder) {
- MVKImage* xfrImage = cmdEncoder->getCommandEncodingPool()->getTransferMVKImage(_transferImageData);
- id<MTLTexture> xfrMTLTex = xfrImage->getMTLTexture();
- id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
- if ( !xfrMTLTex || !dstMTLTex ) { return; }
+ size_t vkIRCnt = _vkImageResolves.size();
+ VkImageBlit expansionRegions[vkIRCnt];
+ VkImageCopy copyRegions[vkIRCnt];
- // Expand the current content of the destination image to the temporary transfer image.
- // Create and execute a temporary BLIT image command.
- // To be threadsafe...do NOT acquire and return the command from the pool.
- uint32_t expRgnCnt = uint32_t(_expansionRegions.size());
- if (expRgnCnt > 0) {
- MVKCmdBlitImage<N> expandCmd;
- expandCmd.setContent(cmdEncoder->_cmdBuffer,
- (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
- expRgnCnt, _expansionRegions.data(),
- VK_FILTER_LINEAR, kMVKCommandUseResolveExpandImage);
- expandCmd.encode(cmdEncoder);
- }
+ uint32_t layerCnt = 0;
+ for (VkImageResolve& vkIR : _vkImageResolves) { layerCnt += vkIR.dstSubresource.layerCount; }
+ MVKMetalResolveSlice mtlResolveSlices[layerCnt];
- // Copy the resolve regions of the source image to the temporary transfer image.
- // Create and execute a temporary copy image command.
- // To be threadsafe...do NOT acquire and return the command from the pool.
- uint32_t cpyRgnCnt = uint32_t(_copyRegions.size());
- if (cpyRgnCnt > 0) {
- MVKCmdCopyImage<N> copyCmd;
- copyCmd.setContent(cmdEncoder->_cmdBuffer,
+ uint32_t expCnt = 0;
+ uint32_t copyCnt = 0;
+ uint32_t sliceCnt = 0;
+
+ for (VkImageResolve& vkIR : _vkImageResolves) {
+
+ uint32_t mipLvl = vkIR.dstSubresource.mipLevel;
+ VkExtent3D srcImgExt = _srcImage->getExtent3D(mipLvl);
+ VkExtent3D dstImgExt = _dstImage->getExtent3D(mipLvl);
+
+ // 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
+ // 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) ) {
+ 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) };
+ }
+
+ // 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;
+
+ // Adds a resolve slice struct for each destination layer in the resolve region.
+ uint32_t baseLayer = vkIR.dstSubresource.baseArrayLayer;
+ uint32_t layCnt = vkIR.dstSubresource.layerCount;
+ for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
+ MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sliceCnt++];
+ rslvSlice.level = vkIR.dstSubresource.mipLevel;
+ rslvSlice.slice = baseLayer + layIdx;
+ }
+ }
+
+ id<MTLTexture> srcMTLTex;
+ if (expCnt == 0) {
+ // Expansion and copying is not required. Each mip level of the source image
+ // is being resolved entirely. Resolve directly from the source image.
+ srcMTLTex = _srcImage->getMTLTexture();
+
+ } else {
+ // 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.
+ MVKImageDescriptorData xferImageData;
+ _dstImage->getTransferDescriptorData(xferImageData);
+ xferImageData.samples = _srcImage->getSampleCount();
+ MVKImage* 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, kMVKCommandUseResolveExpandImage);
+ expCmd.encode(cmdEncoder);
+
+ // Copy the resolve regions of the source image to the temporary transfer image.
+ MVKCmdCopyImage<N> copyCmd;
+ copyCmd.setContent(cmdEncoder->_cmdBuffer,
(VkImage)_srcImage, _srcLayout, (VkImage)xfrImage, _dstLayout,
- cpyRgnCnt, _copyRegions.data(), kMVKCommandUseResolveCopyImage);
- copyCmd.encode(cmdEncoder);
- }
+ copyCnt, copyRegions, kMVKCommandUseResolveCopyImage);
+ copyCmd.encode(cmdEncoder);
- cmdEncoder->endCurrentMetalEncoding();
+ srcMTLTex = xfrImage->getMTLTexture();
+ }
- MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
- mtlColorAttDesc.texture = xfrMTLTex;
- mtlColorAttDesc.resolveTexture = dstMTLTex;
+ cmdEncoder->endCurrentMetalEncoding();
- for (auto& rslvSlice : _mtlResolveSlices) {
+ MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor];
+ MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPD.colorAttachments[0];
+ mtlColorAttDesc.loadAction = MTLLoadActionLoad;
+ mtlColorAttDesc.storeAction = MTLStoreActionMultisampleResolve;
+ mtlColorAttDesc.texture = srcMTLTex;
+ mtlColorAttDesc.resolveTexture = _dstImage->getMTLTexture();
- // Update the render pass descriptor for the texture level and slice, and create a render encoder.
- mtlColorAttDesc.level = rslvSlice.level;
- mtlColorAttDesc.slice = rslvSlice.slice;
- mtlColorAttDesc.resolveLevel = rslvSlice.level;
- mtlColorAttDesc.resolveSlice = rslvSlice.slice;
- id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: _mtlRenderPassDescriptor];
+ // For each resolve slice, update the render pass descriptor for
+ // the texture level and slice and create a render encoder.
+ for (uint32_t sIdx = 0; sIdx < sliceCnt; sIdx++) {
+ MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sIdx];
+ mtlColorAttDesc.level = rslvSlice.level;
+ mtlColorAttDesc.slice = rslvSlice.slice;
+ mtlColorAttDesc.resolveLevel = rslvSlice.level;
+ mtlColorAttDesc.resolveSlice = rslvSlice.slice;
+ id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(kMVKCommandUseResolveImage));
- [mtlRendEnc pushDebugGroup: @"vkCmdResolveImage"];
- [mtlRendEnc popDebugGroup];
- [mtlRendEnc endEncoding];
- }
-}
-
-template <size_t N>
-MVKCmdResolveImage<N>::MVKCmdResolveImage() {
- initMTLRenderPassDescriptor();
-}
-
-// Create and configure the render pass descriptor
-template <size_t N>
-void MVKCmdResolveImage<N>::initMTLRenderPassDescriptor() {
- _mtlRenderPassDescriptor = [[MTLRenderPassDescriptor renderPassDescriptor] retain]; // retained
- MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
- mtlColorAttDesc.loadAction = MTLLoadActionLoad;
- mtlColorAttDesc.storeAction = MTLStoreActionMultisampleResolve;
-}
-
-template <size_t N>
-MVKCmdResolveImage<N>::~MVKCmdResolveImage() {
- [_mtlRenderPassDescriptor release];
+ [mtlRendEnc pushDebugGroup: @"vkCmdResolveImage"];
+ [mtlRendEnc popDebugGroup];
+ [mtlRendEnc endEncoding];
+ }
}
template class MVKCmdResolveImage<1>;