Merge pull request #1053 from cdavis5e/max-inline-uniform-blocks
MVKDevice: Limit the maximum number of inline uniform blocks on Mac.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 654b719..5f0a1f4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -419,11 +419,19 @@
}
MVKFormatType mvkFmt = _pixelFormats.getFormatType(format);
+ bool isChromaSubsampled = _pixelFormats.getChromaSubsamplingPlaneCount(format) > 0;
+ bool isMultiPlanar = _pixelFormats.getChromaSubsamplingPlaneCount(format) > 1;
+ bool isBGRG = isChromaSubsampled && !isMultiPlanar && _pixelFormats.getBlockTexelSize(format).width > 1;
bool hasAttachmentUsage = mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
+ // Disjoint memory requires a multiplanar format.
+ if (!isMultiPlanar && mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_DISJOINT_BIT)) {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
VkPhysicalDeviceLimits* pLimits = &_properties.limits;
VkExtent3D maxExt = { 1, 1, 1};
uint32_t maxLevels = 1;
@@ -453,11 +461,14 @@
// Metal does not allow compressed or depth/stencil formats on native 1D textures
if (mvkFmt == kMVKFormatDepthStencil) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
if (mvkFmt == kMVKFormatCompressed) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
+ if (isChromaSubsampled) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
}
break;
case VK_IMAGE_TYPE_2D:
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
+ // Chroma-subsampled cube images aren't supported.
+ if (isChromaSubsampled) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
maxExt.width = pLimits->maxImageDimensionCube;
maxExt.height = pLimits->maxImageDimensionCube;
} else {
@@ -467,15 +478,16 @@
maxExt.depth = 1;
if (tiling == VK_IMAGE_TILING_LINEAR) {
// Linear textures have additional restrictions under Metal:
- // - They may not be depth/stencil or compressed textures.
- if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed) {
+ // - They may not be depth/stencil, compressed, or chroma subsampled textures.
+ // We allow multi-planar formats because those internally use non-subsampled formats.
+ if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed || isBGRG) {
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
#if MVK_MACOS
// - On macOS, Linear textures may not be used as framebuffer attachments.
if (hasAttachmentUsage) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
#endif
- // Linear textures may only have one mip level. layer & sample
+ // Linear textures may only have one mip level, layer & sample.
maxLevels = 1;
maxLayers = 1;
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
@@ -483,14 +495,22 @@
VkFormatProperties fmtProps;
getFormatProperties(format, &fmtProps);
// Compressed multisampled textures aren't supported.
+ // Chroma-subsampled multisampled textures aren't supported.
// Multisampled cube textures aren't supported.
// Non-renderable multisampled textures aren't supported.
- if (mvkFmt == kMVKFormatCompressed ||
+ if (mvkFmt == kMVKFormatCompressed || isChromaSubsampled ||
mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ||
!mvkIsAnyFlagEnabled(fmtProps.optimalTilingFeatures, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ) {
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
}
- maxLevels = mvkMipmapLevels3D(maxExt);
+ // BGRG and GBGR images may only have one mip level and one layer.
+ // Other chroma subsampled formats may have multiple mip levels, but still only one layer.
+ if (isChromaSubsampled) {
+ maxLevels = isBGRG ? 1 : mvkMipmapLevels3D(maxExt);
+ maxLayers = 1;
+ } else {
+ maxLevels = mvkMipmapLevels3D(maxExt);
+ }
}
break;
@@ -500,7 +520,8 @@
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
// Metal does not allow compressed or depth/stencil formats on 3D textures
- if (mvkFmt == kMVKFormatDepthStencil
+ if (mvkFmt == kMVKFormatDepthStencil ||
+ isChromaSubsampled
#if MVK_IOS_OR_TVOS
|| mvkFmt == kMVKFormatCompressed
#endif
@@ -560,7 +581,7 @@
switch (nextProps->sType) {
case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: {
auto* samplerYcbcrConvProps = (VkSamplerYcbcrConversionImageFormatProperties*)nextProps;
- samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = _pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format);
+ samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = std::max(_pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format), (uint8_t)1u);
break;
}
default:
@@ -1520,7 +1541,6 @@
uint32_t maxStorage = 0, maxUniform = 0;
bool singleTexelStorage = true, singleTexelUniform = true;
_pixelFormats.enumerateSupportedFormats({0, 0, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT}, true, [&](VkFormat vk) {
- if ( _pixelFormats.getChromaSubsamplingComponentBits(vk) > 0 ) { return false; } // Skip chroma subsampling formats
MTLPixelFormat mtlFmt = _pixelFormats.getMTLPixelFormat(vk);
if ( !mtlFmt ) { return false; } // If format is invalid, avoid validation errors on MTLDevice format alignment calls
@@ -2964,8 +2984,15 @@
VkDeviceSize MVKDevice::getVkFormatTexelBufferAlignment(VkFormat format, MVKBaseObject* mvkObj) {
VkDeviceSize deviceAlignment = 0;
id<MTLDevice> mtlDev = getMTLDevice();
+ MVKPixelFormats* mvkPixFmts = getPixelFormats();
if ([mtlDev respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)]) {
- deviceAlignment = [mtlDev minimumLinearTextureAlignmentForPixelFormat: getPixelFormats()->getMTLPixelFormat(format)];
+ MTLPixelFormat mtlPixFmt = mvkPixFmts->getMTLPixelFormat(format);
+ 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.
+ mtlPixFmt = mvkPixFmts->getChromaSubsamplingPlaneMTLPixelFormat(format, 1);
+ }
+ deviceAlignment = [mtlDev minimumLinearTextureAlignmentForPixelFormat: mtlPixFmt];
}
return deviceAlignment ? deviceAlignment : _pProperties->limits.minTexelBufferOffsetAlignment;
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 210c1ff..4a48b3e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -529,7 +529,7 @@
VkExtent3D MVKImage::getExtent3D(uint8_t planeIndex, uint32_t mipLevel) {
VkExtent3D extent = _extent;
- if (_hasChromaSubsampling) {
+ if (_hasChromaSubsampling && planeIndex > 0) {
extent.width /= _planes[planeIndex]->_blockTexelSize.width;
extent.height /= _planes[planeIndex]->_blockTexelSize.height;
}
@@ -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,
@@ -881,6 +883,10 @@
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling cannot be used with compressed images. Setting sample count to 1."));
validSamples = VK_SAMPLE_COUNT_1_BIT;
}
+ if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) > 0) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling cannot be used with chroma subsampled images. Setting sample count to 1."));
+ validSamples = VK_SAMPLE_COUNT_1_BIT;
+ }
if (pCreateInfo->arrayLayers > 1) {
if ( !_device->_pMetalFeatures->multisampleArrayTextures ) {
@@ -901,6 +907,7 @@
bool is2D = (getImageType() == VK_IMAGE_TYPE_2D);
bool isCompressed = pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatCompressed;
+ bool isChromaSubsampled = pixFmts->getChromaSubsamplingPlaneCount(pCreateInfo->format) > 0;
#if MVK_IOS_OR_TVOS
if (isCompressed && !is2D) {
@@ -917,6 +924,16 @@
}
#endif
+ if (isChromaSubsampled && !is2D) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, chroma subsampled formats may only be used with 2D images."));
+ }
+ if (isChromaSubsampled && mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, chroma subsampled formats may not be used with cube images."));
+ }
+ if (isChromaSubsampled && (pCreateInfo->arrayLayers > 1)) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Chroma-subsampled formats may only have one array layer."));
+ }
+
if ((pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatDepthStencil) && !is2D ) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, depth/stencil formats may only be used with 2D images."));
}
@@ -940,6 +957,10 @@
if (validMipLevels == 1) { return validMipLevels; }
+ if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) == 1) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, GBGR and BGRG images cannot use mipmaps. Setting mip levels to 1."));
+ validMipLevels = 1;
+ }
if (getImageType() == VK_IMAGE_TYPE_1D) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, native 1D images cannot use mipmaps. Setting mip levels to 1. Consider enabling MVK_CONFIG_TEXTURE_1D_AS_2D."));
validMipLevels = 1;
@@ -967,6 +988,10 @@
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, format must not be a compressed format."));
isLin = false;
}
+ if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) == 1) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, format must not be a single-plane chroma subsampled format."));
+ isLin = false;
+ }
if (pCreateInfo->mipLevels > 1) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, mipLevels must be 1."));
@@ -1311,7 +1336,7 @@
mtlTextureType = MTLTextureType3D;
sliceRange = NSMakeRange(0, 1);
}
- id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(MVKImage::getPlaneFromVkImageAspectFlags(_imageView->_subresourceRange.aspectMask));
+ id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(_planeIndex);
if (_device->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
return [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
textureType: mtlTextureType
@@ -1464,15 +1489,15 @@
beginPlaneIndex = 0,
endPlaneIndex = subsamplingPlaneCount;
if (subsamplingPlaneCount == 0) {
- endPlaneIndex = 1;
- mtlPixFmtOfPlane[0] = getPixelFormats()->getMTLPixelFormat(pCreateInfo->format);
+ if (_subresourceRange.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
+ beginPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(_subresourceRange.aspectMask);
+ }
+ endPlaneIndex = beginPlaneIndex + 1;
+ mtlPixFmtOfPlane[beginPlaneIndex] = getPixelFormats()->getMTLPixelFormat(pCreateInfo->format);
} else {
if (!mvkVkComponentMappingsMatch(pCreateInfo->components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A})) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Image view swizzling for multi planar formats is not supported."));
}
- if (_subresourceRange.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
- beginPlaneIndex = endPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(_subresourceRange.aspectMask);
- }
}
for (uint8_t planeIndex = beginPlaneIndex; planeIndex < endPlaneIndex; planeIndex++) {
_planes.push_back(new MVKImageViewPlane(this, planeIndex, mtlPixFmtOfPlane[planeIndex], pCreateInfo));
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 d27b4b2..7d71cbe 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -190,7 +190,7 @@
// If the MTLPixelFormat is not supported but VkFormat is valid,
// attempt to substitute a different format and potentially report an error.
- if ( !mtlPixFmt && vkFormat ) {
+ if ( !mtlPixFmt && vkFormat && vkDesc.chromaSubsamplingPlaneCount <= 1 ) {
mtlPixFmt = vkDesc.mtlPixelFormatSubstitute;
// Report an error if there is no substitute, or the first time a substitution is made.
@@ -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);
@@ -273,7 +290,7 @@
return 0;
case 1:
bytesPerBlock[0] *= 4;
- mtlPixFmt[0] = (bits == 8) ? MTLPixelFormatRGBA8Unorm : MTLPixelFormatRGBA16Unorm;
+ mtlPixFmt[0] = getMTLPixelFormat(vkFormat);
break;
case 2:
blockTexelSize[0] = VkExtent2D{1, 1};
@@ -837,9 +854,9 @@
addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_422_UNORM, Invalid, 3, 8, 2, 1, 4 );
addVkFormatDescChromaSubsampling( G8_B8R8_2PLANE_422_UNORM, Invalid, 2, 8, 2, 1, 4 );
addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_444_UNORM, Invalid, 3, 8, 1, 1, 3 );
- addVkFormatDescChromaSubsampling( R10X6_UNORM_PACK16, Invalid, 0, 10, 1, 1, 2 );
- addVkFormatDescChromaSubsampling( R10X6G10X6_UNORM_2PACK16, Invalid, 0, 10, 1, 1, 4 );
- addVkFormatDescChromaSubsampling( R10X6G10X6B10X6A10X6_UNORM_4PACK16, Invalid, 0, 10, 1, 1, 8 );
+ addVkFormatDescChromaSubsampling( R10X6_UNORM_PACK16, R16Unorm, 0, 10, 1, 1, 2 );
+ addVkFormatDescChromaSubsampling( R10X6G10X6_UNORM_2PACK16, RG16Unorm, 0, 10, 1, 1, 4 );
+ addVkFormatDescChromaSubsampling( R10X6G10X6B10X6A10X6_UNORM_4PACK16, RGBA16Unorm, 0, 10, 1, 1, 8 );
addVkFormatDescChromaSubsampling( G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
addVkFormatDescChromaSubsampling( B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, Invalid, 3, 10, 2, 2, 12 );
@@ -847,9 +864,9 @@
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, Invalid, 3, 10, 2, 1, 8 );
addVkFormatDescChromaSubsampling( G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, Invalid, 2, 10, 2, 1, 8 );
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, Invalid, 3, 10, 1, 1, 6 );
- addVkFormatDescChromaSubsampling( R12X4_UNORM_PACK16, Invalid, 0, 12, 1, 1, 2 );
- addVkFormatDescChromaSubsampling( R12X4G12X4_UNORM_2PACK16, Invalid, 0, 12, 1, 1, 4 );
- addVkFormatDescChromaSubsampling( R12X4G12X4B12X4A12X4_UNORM_4PACK16, Invalid, 0, 12, 1, 1, 8 );
+ addVkFormatDescChromaSubsampling( R12X4_UNORM_PACK16, R16Unorm, 0, 12, 1, 1, 2 );
+ addVkFormatDescChromaSubsampling( R12X4G12X4_UNORM_2PACK16, RG16Unorm, 0, 12, 1, 1, 4 );
+ addVkFormatDescChromaSubsampling( R12X4G12X4B12X4A12X4_UNORM_4PACK16, RGBA16Unorm, 0, 12, 1, 1, 8 );
addVkFormatDescChromaSubsampling( G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
addVkFormatDescChromaSubsampling( B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
addVkFormatDescChromaSubsampling( G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, Invalid, 3, 12, 2, 2, 12 );
@@ -1620,9 +1637,7 @@
kMVKVkFormatFeatureFlagsTexDSAtt = (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT),
kMVKVkFormatFeatureFlagsTexBlend = (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT),
kMVKVkFormatFeatureFlagsTexTransfer = (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
- VK_FORMAT_FEATURE_BLIT_SRC_BIT |
- VK_FORMAT_FEATURE_BLIT_DST_BIT),
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT),
kMVKVkFormatFeatureFlagsTexChromaSubsampling = (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR),
kMVKVkFormatFeatureFlagsTexMultiPlanar = (VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR |
@@ -1650,12 +1665,13 @@
vkProps.linearTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
// Chroma subsampling and multi planar features
- if (getChromaSubsamplingComponentBits(vkDesc.vkFormat) > 0) {
- vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
- }
uint8_t chromaSubsamplingPlaneCount = getChromaSubsamplingPlaneCount(vkDesc.vkFormat);
- if (chromaSubsamplingPlaneCount > 0) {
- mtlPixFmtCaps = kMVKMTLFmtCapsRF;
+ uint8_t chromaSubsamplingComponentBits = getChromaSubsamplingComponentBits(vkDesc.vkFormat);
+ if (chromaSubsamplingComponentBits > 0) {
+ if (mtlPixFmtCaps != 0 || chromaSubsamplingPlaneCount > 1) {
+ mtlPixFmtCaps = kMVKMTLFmtCapsRF;
+ vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
+ }
enableFormatFeatures(ChromaSubsampling, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
}
if (chromaSubsamplingPlaneCount > 1) {
@@ -1670,8 +1686,15 @@
enableFormatFeatures(DSAtt, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
enableFormatFeatures(Blend, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
+ if (chromaSubsamplingComponentBits > 0) {
+ // Vulkan forbids blits between chroma-subsampled formats.
+ mvkDisableFlags(vkProps.optimalTilingFeatures, (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT));
+ }
+
// Linear tiling is not available to depth/stencil or compressed formats.
- if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed) ) {
+ // GBGR and BGRG formats also do not support linear tiling in Metal.
+ if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed ||
+ (chromaSubsamplingPlaneCount == 1 && vkDesc.blockTexelSize.width > 1)) ) {
// Start with optimal tiling features, and modify.
vkProps.linearTilingFeatures = vkProps.optimalTilingFeatures;
@@ -1686,9 +1709,10 @@
#endif
}
- // Texel buffers are not available to depth/stencil or compressed formats.
+ // Texel buffers are not available to depth/stencil, compressed, or chroma subsampled formats.
vkProps.bufferFeatures = kMVKVkFormatFeatureFlagsTexNone;
- if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed) ) {
+ if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed ||
+ chromaSubsamplingComponentBits > 0) ) {
enableFormatFeatures(Read, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
enableFormatFeatures(Write, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
enableFormatFeatures(Atomic, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);