From 1748686d0d1cca78245f438d22078d9c548fdc60 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 6 Jul 2021 14:19:26 -0400 Subject: [PATCH] Refactor MVKImageView::validateSwizzledMTLPixelFormat(). Move MVKImageView::validateSwizzledMTLPixelFormat() to MVKImageViewPlane::initSwizzledMTLPixelFormat(), make it non-static, and use instance member content instead of passing all the data as function arguments. --- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 26 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 356 +++++++++++------------ 2 files changed, 175 insertions(+), 207 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index ff719db4..95534996 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -536,6 +536,7 @@ public: protected: void propagateDebugName(); id newMTLTexture(); + VkResult initSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo); MVKImageViewPlane(MVKImageView* imageView, uint8_t planeIndex, MTLPixelFormat mtlPixFmt, const VkImageViewCreateInfo* pCreateInfo); friend MVKImageView; @@ -545,6 +546,7 @@ protected: uint32_t _packedSwizzle; id _mtlTexture; bool _useMTLTextureView; + bool _useSwizzle; }; @@ -591,30 +593,6 @@ public: */ void populateMTLRenderPassAttachmentDescriptorResolve(MTLRenderPassAttachmentDescriptor* mtlAttDesc); - /** - * Returns, in mtlPixFmt, a MTLPixelFormat, based on the MTLPixelFormat converted from - * the VkFormat, but possibly modified by the swizzles defined in the VkComponentMapping - * of the VkImageViewCreateInfo. - * - * Metal prior to version 3.0 does not support native per-texture swizzles, so if the swizzle - * is not an identity swizzle, this function attempts to find an alternate MTLPixelFormat that - * coincidentally matches the swizzled format. - * - * If a replacement MTLFormat was found, it is returned and useSwizzle is set to false. - * If a replacement MTLFormat could not be found, the original MTLPixelFormat is returned, - * and the useSwizzle is set to true, indicating that either native or shader swizzling - * should be used for this image view. - * - * This is a static function that can be used to validate image view formats prior to creating one. - */ - static VkResult validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo, - VkImageUsageFlags usage, - MVKVulkanAPIObject* apiObject, - bool hasNativeSwizzleSupport, - bool hasShaderSwizzleSupport, - MTLPixelFormat& mtlPixFmt, - bool& useSwizzle); - #pragma mark Construction diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 2dedcec3..18a74e22 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1474,15 +1474,8 @@ MVKImageViewPlane::MVKImageViewPlane(MVKImageView* imageView, _mtlPixFmt = mtlPixFmt; _mtlTexture = nil; - bool useSwizzle; - _imageView->setConfigurationResult(_imageView->validateSwizzledMTLPixelFormat(pCreateInfo, - _imageView->_usage, - _imageView, - _device->_pMetalFeatures->nativeTextureSwizzle, - mvkConfig().fullImageViewSwizzle, - _mtlPixFmt, - useSwizzle)); - _packedSwizzle = (useSwizzle) ? mvkPackSwizzle(pCreateInfo->components) : 0; + getVulkanAPIObject()->setConfigurationResult(initSwizzledMTLPixelFormat(pCreateInfo)); + _packedSwizzle = _useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0; // Determine whether this image view should use a Metal texture view, // and set the _useMTLTextureView variable appropriately. @@ -1503,6 +1496,177 @@ MVKImageViewPlane::MVKImageViewPlane(MVKImageView* imageView, } } +VkResult MVKImageViewPlane::initSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo) { + + _useSwizzle = false; + VkComponentMapping components = pCreateInfo->components; + +#define SWIZZLE_MATCHES(R, G, B, A) mvkVkComponentMappingsMatch(components, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} ) +#define VK_COMPONENT_SWIZZLE_ANY VK_COMPONENT_SWIZZLE_MAX_ENUM + + // If we have an identity swizzle, we're all good. + if (SWIZZLE_MATCHES(R, G, B, A)) { + // Change to stencil-only format if only stencil aspect is requested + if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && + mvkIsAnyFlagEnabled(_imageView->_usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { + if (_mtlPixFmt == MTLPixelFormatDepth32Float_Stencil8) { + _mtlPixFmt = MTLPixelFormatX32_Stencil8; + } +#if MVK_MACOS + else if (_mtlPixFmt == MTLPixelFormatDepth24Unorm_Stencil8) { + _mtlPixFmt = MTLPixelFormatX24_Stencil8; + } +#endif + } + + return VK_SUCCESS; + } + + if (mvkIsAnyFlagEnabled(_imageView->_usage, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) { + // Vulkan forbids using image views with non-identity swizzles as storage images or attachments. + // Let's catch some cases which are essentially identity, but would still result in Metal restricting + // the resulting texture's usage. + + switch (_mtlPixFmt) { + case MTLPixelFormatR8Unorm: +#if MVK_APPLE_SILICON + case MTLPixelFormatR8Unorm_sRGB: +#endif + case MTLPixelFormatR8Snorm: + case MTLPixelFormatR8Uint: + case MTLPixelFormatR8Sint: + case MTLPixelFormatR16Unorm: + case MTLPixelFormatR16Snorm: + case MTLPixelFormatR16Uint: + case MTLPixelFormatR16Sint: + case MTLPixelFormatR16Float: + case MTLPixelFormatR32Uint: + case MTLPixelFormatR32Sint: + case MTLPixelFormatR32Float: + if (SWIZZLE_MATCHES(R, ZERO, ZERO, ONE)) { + return VK_SUCCESS; + } + break; + + case MTLPixelFormatRG8Unorm: +#if MVK_APPLE_SILICON + case MTLPixelFormatRG8Unorm_sRGB: +#endif + case MTLPixelFormatRG8Snorm: + case MTLPixelFormatRG8Uint: + case MTLPixelFormatRG8Sint: + case MTLPixelFormatRG16Unorm: + case MTLPixelFormatRG16Snorm: + case MTLPixelFormatRG16Uint: + case MTLPixelFormatRG16Sint: + case MTLPixelFormatRG16Float: + case MTLPixelFormatRG32Uint: + case MTLPixelFormatRG32Sint: + case MTLPixelFormatRG32Float: + if (SWIZZLE_MATCHES(R, G, ZERO, ONE)) { + return VK_SUCCESS; + } + break; + + case MTLPixelFormatRG11B10Float: + case MTLPixelFormatRGB9E5Float: + if (SWIZZLE_MATCHES(R, G, B, ONE)) { + return VK_SUCCESS; + } + break; + + default: + break; + } + } + + switch (_mtlPixFmt) { + case MTLPixelFormatR8Unorm: + if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) { + _mtlPixFmt = MTLPixelFormatA8Unorm; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatA8Unorm: + if (SWIZZLE_MATCHES(A, ANY, ANY, ZERO)) { + _mtlPixFmt = MTLPixelFormatR8Unorm; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatRGBA8Unorm: + if (SWIZZLE_MATCHES(B, G, R, A)) { + _mtlPixFmt = MTLPixelFormatBGRA8Unorm; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatRGBA8Unorm_sRGB: + if (SWIZZLE_MATCHES(B, G, R, A)) { + _mtlPixFmt = MTLPixelFormatBGRA8Unorm_sRGB; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatBGRA8Unorm: + if (SWIZZLE_MATCHES(B, G, R, A)) { + _mtlPixFmt = MTLPixelFormatRGBA8Unorm; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatBGRA8Unorm_sRGB: + if (SWIZZLE_MATCHES(B, G, R, A)) { + _mtlPixFmt = MTLPixelFormatRGBA8Unorm_sRGB; + return VK_SUCCESS; + } + break; + + case MTLPixelFormatDepth32Float_Stencil8: + // If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed + if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && + mvkIsAnyFlagEnabled(_imageView->_usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { + _mtlPixFmt = MTLPixelFormatX32_Stencil8; + if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) { + return VK_SUCCESS; + } + } + break; + +#if MVK_MACOS + case MTLPixelFormatDepth24Unorm_Stencil8: + // If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed + if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && + mvkIsAnyFlagEnabled(_imageView->_usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { + _mtlPixFmt = MTLPixelFormatX24_Stencil8; + if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) { + return VK_SUCCESS; + } + } + break; +#endif + + default: + break; + } + + // No format transformation swizzles were found, so we'll need to use either native or shader swizzling, if it is supported. + if ( !(_device->_pMetalFeatures->nativeTextureSwizzle || mvkConfig().fullImageViewSwizzle) ) { + return getVulkanAPIObject()->reportError(VK_ERROR_FEATURE_NOT_PRESENT, + "The value of %s::components) (%s, %s, %s, %s), when applied to a VkImageView, requires full component swizzling to be enabled both at the" + " time when the VkImageView is created and at the time any pipeline that uses that VkImageView is compiled. Full component swizzling can" + " be enabled via the MVKConfiguration::fullImageViewSwizzle config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable.", + pCreateInfo->image ? "vkCreateImageView(VkImageViewCreateInfo" : "vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDeviceImageViewSupportEXTX", + mvkVkComponentSwizzleName(components.r), mvkVkComponentSwizzleName(components.g), + mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a)); + } + + _useSwizzle = true; + + return VK_SUCCESS; +} + MVKImageViewPlane::~MVKImageViewPlane() { [_mtlTexture release]; } @@ -1635,180 +1799,6 @@ MVKImageView::MVKImageView(MVKDevice* device, } } -VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo, - VkImageUsageFlags usage, - MVKVulkanAPIObject* apiObject, - bool hasNativeSwizzleSupport, - bool hasShaderSwizzleSupport, - MTLPixelFormat& mtlPixFmt, - bool& useSwizzle) { - useSwizzle = false; - VkComponentMapping components = pCreateInfo->components; - - #define SWIZZLE_MATCHES(R, G, B, A) mvkVkComponentMappingsMatch(components, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} ) - #define VK_COMPONENT_SWIZZLE_ANY VK_COMPONENT_SWIZZLE_MAX_ENUM - - // If we have an identity swizzle, we're all good. - if (SWIZZLE_MATCHES(R, G, B, A)) { - // Change to stencil-only format if only stencil aspect is requested - if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && - mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { - if (mtlPixFmt == MTLPixelFormatDepth32Float_Stencil8) - mtlPixFmt = MTLPixelFormatX32_Stencil8; -#if MVK_MACOS - else if (mtlPixFmt == MTLPixelFormatDepth24Unorm_Stencil8) - mtlPixFmt = MTLPixelFormatX24_Stencil8; -#endif - } - - return VK_SUCCESS; - } - - if (mvkIsAnyFlagEnabled(usage, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) { - // Vulkan forbids using image views with non-identity swizzles as storage images or attachments. - // Let's catch some cases which are essentially identity, but would still result in Metal restricting - // the resulting texture's usage. - - switch (mtlPixFmt) { - case MTLPixelFormatR8Unorm: -#if MVK_APPLE_SILICON - case MTLPixelFormatR8Unorm_sRGB: -#endif - case MTLPixelFormatR8Snorm: - case MTLPixelFormatR8Uint: - case MTLPixelFormatR8Sint: - case MTLPixelFormatR16Unorm: - case MTLPixelFormatR16Snorm: - case MTLPixelFormatR16Uint: - case MTLPixelFormatR16Sint: - case MTLPixelFormatR16Float: - case MTLPixelFormatR32Uint: - case MTLPixelFormatR32Sint: - case MTLPixelFormatR32Float: - if (SWIZZLE_MATCHES(R, ZERO, ZERO, ONE)) { - return VK_SUCCESS; - } - break; - - case MTLPixelFormatRG8Unorm: -#if MVK_APPLE_SILICON - case MTLPixelFormatRG8Unorm_sRGB: -#endif - case MTLPixelFormatRG8Snorm: - case MTLPixelFormatRG8Uint: - case MTLPixelFormatRG8Sint: - case MTLPixelFormatRG16Unorm: - case MTLPixelFormatRG16Snorm: - case MTLPixelFormatRG16Uint: - case MTLPixelFormatRG16Sint: - case MTLPixelFormatRG16Float: - case MTLPixelFormatRG32Uint: - case MTLPixelFormatRG32Sint: - case MTLPixelFormatRG32Float: - if (SWIZZLE_MATCHES(R, G, ZERO, ONE)) { - return VK_SUCCESS; - } - break; - - case MTLPixelFormatRG11B10Float: - case MTLPixelFormatRGB9E5Float: - if (SWIZZLE_MATCHES(R, G, B, ONE)) { - return VK_SUCCESS; - } - break; - - default: - break; - } - } - - switch (mtlPixFmt) { - case MTLPixelFormatR8Unorm: - if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) { - mtlPixFmt = MTLPixelFormatA8Unorm; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatA8Unorm: - if (SWIZZLE_MATCHES(A, ANY, ANY, ZERO)) { - mtlPixFmt = MTLPixelFormatR8Unorm; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatRGBA8Unorm: - if (SWIZZLE_MATCHES(B, G, R, A)) { - mtlPixFmt = MTLPixelFormatBGRA8Unorm; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatRGBA8Unorm_sRGB: - if (SWIZZLE_MATCHES(B, G, R, A)) { - mtlPixFmt = MTLPixelFormatBGRA8Unorm_sRGB; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatBGRA8Unorm: - if (SWIZZLE_MATCHES(B, G, R, A)) { - mtlPixFmt = MTLPixelFormatRGBA8Unorm; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatBGRA8Unorm_sRGB: - if (SWIZZLE_MATCHES(B, G, R, A)) { - mtlPixFmt = MTLPixelFormatRGBA8Unorm_sRGB; - return VK_SUCCESS; - } - break; - - case MTLPixelFormatDepth32Float_Stencil8: - // If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed - if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && - mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { - mtlPixFmt = MTLPixelFormatX32_Stencil8; - if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) { - return VK_SUCCESS; - } - } - break; - -#if MVK_MACOS - case MTLPixelFormatDepth24Unorm_Stencil8: - // If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed - if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && - mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) { - mtlPixFmt = MTLPixelFormatX24_Stencil8; - if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) { - return VK_SUCCESS; - } - } - break; -#endif - - default: - break; - } - - // No format transformation swizzles were found, so we'll need to use either native or shader swizzling. - useSwizzle = true; - if (hasNativeSwizzleSupport || hasShaderSwizzleSupport ) { - return VK_SUCCESS; - } - - // Oh, oh. Neither native or shader swizzling is supported. - return apiObject->reportError(VK_ERROR_FEATURE_NOT_PRESENT, - "The value of %s::components) (%s, %s, %s, %s), when applied to a VkImageView, requires full component swizzling to be enabled both at the" - " time when the VkImageView is created and at the time any pipeline that uses that VkImageView is compiled. Full component swizzling can" - " be enabled via the MVKConfiguration::fullImageViewSwizzle config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable.", - pCreateInfo->image ? "vkCreateImageView(VkImageViewCreateInfo" : "vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDeviceImageViewSupportEXTX", - mvkVkComponentSwizzleName(components.r), mvkVkComponentSwizzleName(components.g), - mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a)); -} - MVKImageView::~MVKImageView() { mvkDestroyContainerContents(_planes); }