MVKImage: Use the plane's MTLPixelFormat to calculate memory sizes.
We really don't want to use the `VkFormat` for the whole image. That has
a block size set on it, which causes the size to be reduced by a factor
of two or even four, in the case of a 420 format whose pitch exceeds the
required alignment. If instead we use the plane `MTLPixelFormat`, we can
sidestep that.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index ca24eb1..7ac270a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -2986,11 +2986,7 @@
if (mvkPixFmts->getChromaSubsamplingPlaneCount(format) >= 2) {
// Use plane 1 to get the alignment requirements. In a 2-plane format, this will
// typically have stricter alignment requirements due to it being a 2-component format.
- VkExtent2D blockTexelSize[3];
- uint32_t bytesPerBlock[3];
- MTLPixelFormat planePixFmts[3];
- mvkPixFmts->getChromaSubsamplingPlanes(format, blockTexelSize, bytesPerBlock, planePixFmts);
- mtlPixFmt = planePixFmts[1];
+ mtlPixFmt = mvkPixFmts->getChromaSubsamplingPlaneMTLPixelFormat(format, 1);
}
deviceAlignment = [mtlDev minimumLinearTextureAlignmentForPixelFormat: mtlPixFmt];
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 5407e26..72bde4e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -537,14 +537,16 @@
}
VkDeviceSize MVKImage::getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel) {
- size_t bytesPerRow = getPixelFormats()->getBytesPerRow(_vkFormat, getExtent3D(planeIndex, mipLevel).width);
+ MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
+ size_t bytesPerRow = getPixelFormats()->getBytesPerRow(planeMTLPixFmt, getExtent3D(planeIndex, mipLevel).width);
return mvkAlignByteCount(bytesPerRow, _rowByteAlignment);
}
VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel) {
+ MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
VkExtent3D extent = getExtent3D(planeIndex, mipLevel);
size_t bytesPerRow = getBytesPerRow(planeIndex, mipLevel);
- return getPixelFormats()->getBytesPerLayer(_vkFormat, bytesPerRow, extent.height);
+ return getPixelFormats()->getBytesPerLayer(planeMTLPixFmt, bytesPerRow, extent.height);
}
VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
index e87063e..c75ec09 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
@@ -256,6 +256,9 @@
/** Returns the MSLFormatResolution of the specified chroma-subsampling (YCbCr) VkFormat */
SPIRV_CROSS_NAMESPACE::MSLFormatResolution getChromaSubsamplingResolution(VkFormat vkFormat);
+ /** Returns the MTLPixelFormat of the specified chroma-subsampling (YCbCr) VkFormat for the specified plane. */
+ MTLPixelFormat getChromaSubsamplingPlaneMTLPixelFormat(VkFormat vkFormat, uint8_t planeIndex);
+
/** Returns the number of planes, blockTexelSize, bytesPerBlock and mtlPixFmt of each plane of the specified chroma-subsampling (YCbCr) VkFormat into the given arrays */
uint8_t getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
index f758b4a..7d71cbe 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -250,6 +250,23 @@
: SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_420;
}
+MTLPixelFormat MVKPixelFormats::getChromaSubsamplingPlaneMTLPixelFormat(VkFormat vkFormat, uint8_t planeIndex) {
+ uint8_t planes = getChromaSubsamplingPlaneCount(vkFormat);
+ uint8_t bits = getChromaSubsamplingComponentBits(vkFormat);
+ switch(planes) {
+ default:
+ case 1:
+ return getMTLPixelFormat(vkFormat);
+ case 2:
+ if (planeIndex == 1) {
+ return (bits == 8) ? MTLPixelFormatRG8Unorm : MTLPixelFormatRG16Unorm;
+ }
+ /* fallthrough */
+ case 3:
+ return (bits == 8) ? MTLPixelFormatR8Unorm : MTLPixelFormatR16Unorm;
+ }
+}
+
uint8_t MVKPixelFormats::getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]) {
uint8_t planes = getChromaSubsamplingPlaneCount(vkFormat);
uint8_t bits = getChromaSubsamplingComponentBits(vkFormat);