@@ -102,15 +102,31 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma
102
102
return VK_SUCCESS;
103
103
}
104
104
105
+ static inline MTLPixelFormat getDepthStencilAspectFormat (const MTLPixelFormat format, const VkImageAspectFlags aspectMask) {
106
+ if (format == MTLPixelFormatDepth32Float_Stencil8 ) {
107
+ if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) return MTLPixelFormatDepth32Float ;
108
+ if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) return MTLPixelFormatStencil8 ;
109
+ }
110
+ #if MVK_MACOS
111
+ if (format == MTLPixelFormatDepth24Unorm_Stencil8 && (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))
112
+ return MTLPixelFormatStencil8 ;
113
+ #endif
114
+ return format;
115
+ }
116
+
105
117
template <size_t N>
106
118
inline VkResult MVKCmdCopyImage<N>::validate(MVKCommandBuffer* cmdBuff, const VkImageCopy2* region) {
107
119
uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags (region->srcSubresource .aspectMask );
108
120
uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags (region->dstSubresource .aspectMask );
109
121
122
+ // If the format is combined depth-stencil, use the format based on the aspect for the following checks.
123
+ auto srcFormat = getDepthStencilAspectFormat (_srcImage->getMTLPixelFormat (srcPlaneIndex), region->srcSubresource .aspectMask );
124
+ auto dstFormat = getDepthStencilAspectFormat (_dstImage->getMTLPixelFormat (dstPlaneIndex), region->dstSubresource .aspectMask );
125
+
110
126
// Validate
111
127
MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats ();
112
128
if ((_dstImage->getSampleCount () != _srcImage->getSampleCount ()) ||
113
- (pixFmts->getBytesPerBlock (_dstImage-> getMTLPixelFormat (dstPlaneIndex)) != pixFmts->getBytesPerBlock (_srcImage-> getMTLPixelFormat (srcPlaneIndex) ))) {
129
+ (pixFmts->getBytesPerBlock (srcFormat) != pixFmts->getBytesPerBlock (dstFormat ))) {
114
130
return cmdBuff->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." );
115
131
}
116
132
return VK_SUCCESS;
@@ -133,17 +149,20 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma
133
149
134
150
MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat (srcPlaneIndex);
135
151
bool isSrcCompressed = _srcImage->getIsCompressed ();
152
+ bool isSrcCombinedDepthStencilAspect = getDepthStencilAspectFormat (srcMTLPixFmt, vkIC.srcSubresource .aspectMask ) != srcMTLPixFmt;
136
153
bool canReinterpretSrc = _srcImage->hasPixelFormatView (srcPlaneIndex);
137
154
138
155
MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat (dstPlaneIndex);
139
156
bool isDstCompressed = _dstImage->getIsCompressed ();
157
+ bool isDstCombinedDepthStencilAspect = getDepthStencilAspectFormat (dstMTLPixFmt, vkIC.dstSubresource .aspectMask ) != dstMTLPixFmt;
140
158
bool canReinterpretDst = _dstImage->hasPixelFormatView (dstPlaneIndex);
141
159
142
160
bool isEitherCompressed = isSrcCompressed || isDstCompressed;
161
+ bool isOneCombinedDepthStencilAspect = isSrcCombinedDepthStencilAspect != isDstCombinedDepthStencilAspect;
143
162
bool canReinterpret = canReinterpretSrc || canReinterpretDst;
144
163
145
164
// If source and destination can't be reinterpreted to matching formats use a temporary intermediary buffer
146
- bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isEitherCompressed || !canReinterpret);
165
+ bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isEitherCompressed || isOneCombinedDepthStencilAspect || !canReinterpret);
147
166
148
167
if (useTempBuffer) {
149
168
// Add copy from source image to temp buffer.
@@ -587,11 +606,23 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma
587
606
588
607
bool isLayeredBlit = blitKey.dstSampleCount > 1 ? mtlFeats.multisampleLayeredRendering : mtlFeats.layeredRendering ;
589
608
590
- uint32_t layCnt = mvkIBR.region .srcSubresource .layerCount == VK_REMAINING_ARRAY_LAYERS ?
609
+ uint32_t srcLayCnt = mvkIBR.region .srcSubresource .layerCount == VK_REMAINING_ARRAY_LAYERS ?
591
610
_srcImage->getLayerCount () - mvkIBR.region .srcSubresource .baseArrayLayer :
592
611
mvkIBR.region .srcSubresource .layerCount ;
612
+ uint32_t dstLayCnt = mvkIBR.region .dstSubresource .layerCount == VK_REMAINING_ARRAY_LAYERS ?
613
+ _dstImage->getLayerCount () - mvkIBR.region .dstSubresource .baseArrayLayer :
614
+ mvkIBR.region .dstSubresource .layerCount ;
615
+ uint32_t layCnt;
616
+ // If either image is 3D, the difference in z offset must:
617
+ // - Equal the difference in z offset of the other subresource, if it is also 3D.
618
+ // - Equal the number of layers in the other subresource, if it is not 3D.
619
+ // Otherwise, the number of layers should be the same.
593
620
if (_dstImage->getMTLTextureType () == MTLTextureType3D ) {
594
621
layCnt = mvkAbsDiff (mvkIBR.region .dstOffsets [1 ].z , mvkIBR.region .dstOffsets [0 ].z );
622
+ } else if (blitKey.srcMTLTextureType == MTLTextureType3D ) {
623
+ layCnt = mvkAbsDiff (mvkIBR.region .srcOffsets [1 ].z , mvkIBR.region .srcOffsets [0 ].z );
624
+ } else {
625
+ layCnt = srcLayCnt;
595
626
}
596
627
if (isLayeredBlit) {
597
628
// In this case, I can blit all layers at once with a layered draw.
@@ -629,14 +660,19 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma
629
660
// In this case, I need to interpolate along the third dimension manually.
630
661
VkExtent3D srcExtent = _srcImage->getExtent3D (srcPlaneIndex, mvkIBR.region .dstSubresource .mipLevel );
631
662
VkOffset3D so0 = mvkIBR.region .srcOffsets [0 ], so1 = mvkIBR.region .srcOffsets [1 ];
632
- VkOffset3D do0 = mvkIBR.region .dstOffsets [0 ], do1 = mvkIBR.region .dstOffsets [1 ];
663
+ // If the dst is also 3D use the z offsets, otherwise use the layers.
664
+ float do0z = mvkIBR.region .dstOffsets [0 ].z , do1z = mvkIBR.region .dstOffsets [1 ].z ;
665
+ if (_dstImage->getMTLTextureType () != MTLTextureType3D ) {
666
+ do0z = mvkIBR.region .dstSubresource .baseArrayLayer ;
667
+ do1z = do0z + dstLayCnt;
668
+ }
633
669
float startZ = (float )so0.z / (float )srcExtent.depth ;
634
670
float endZ = (float )so1.z / (float )srcExtent.depth ;
635
- if (isLayeredBlit && do0. z > do1. z ) {
671
+ if (isLayeredBlit && do0z > do1z ) {
636
672
// Swap start and end points so interpolation moves in the right direction.
637
673
std::swap (startZ, endZ);
638
674
}
639
- zIncr = (endZ - startZ) / mvkAbsDiff (do1. z , do0. z );
675
+ zIncr = (endZ - startZ) / mvkAbsDiff (do1z, do0z );
640
676
float z = startZ + (isLayeredBlit ? 0.0 : (layIdx + 0.5 )) * zIncr;
641
677
for (uint32_t i = 0 ; i < kMVKBlitVertexCount ; ++i) {
642
678
mvkIBR.vertices [i].texCoord .z = z;
0 commit comments