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.
This commit is contained in:
Bill Hollings 2021-07-06 14:19:26 -04:00
parent 9534c3b9ef
commit 1748686d0d
2 changed files with 175 additions and 207 deletions

View File

@ -536,6 +536,7 @@ public:
protected: protected:
void propagateDebugName(); void propagateDebugName();
id<MTLTexture> newMTLTexture(); id<MTLTexture> newMTLTexture();
VkResult initSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo);
MVKImageViewPlane(MVKImageView* imageView, uint8_t planeIndex, MTLPixelFormat mtlPixFmt, const VkImageViewCreateInfo* pCreateInfo); MVKImageViewPlane(MVKImageView* imageView, uint8_t planeIndex, MTLPixelFormat mtlPixFmt, const VkImageViewCreateInfo* pCreateInfo);
friend MVKImageView; friend MVKImageView;
@ -545,6 +546,7 @@ protected:
uint32_t _packedSwizzle; uint32_t _packedSwizzle;
id<MTLTexture> _mtlTexture; id<MTLTexture> _mtlTexture;
bool _useMTLTextureView; bool _useMTLTextureView;
bool _useSwizzle;
}; };
@ -591,30 +593,6 @@ public:
*/ */
void populateMTLRenderPassAttachmentDescriptorResolve(MTLRenderPassAttachmentDescriptor* mtlAttDesc); 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 #pragma mark Construction

View File

@ -1474,15 +1474,8 @@ MVKImageViewPlane::MVKImageViewPlane(MVKImageView* imageView,
_mtlPixFmt = mtlPixFmt; _mtlPixFmt = mtlPixFmt;
_mtlTexture = nil; _mtlTexture = nil;
bool useSwizzle; getVulkanAPIObject()->setConfigurationResult(initSwizzledMTLPixelFormat(pCreateInfo));
_imageView->setConfigurationResult(_imageView->validateSwizzledMTLPixelFormat(pCreateInfo, _packedSwizzle = _useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
_imageView->_usage,
_imageView,
_device->_pMetalFeatures->nativeTextureSwizzle,
mvkConfig().fullImageViewSwizzle,
_mtlPixFmt,
useSwizzle));
_packedSwizzle = (useSwizzle) ? mvkPackSwizzle(pCreateInfo->components) : 0;
// Determine whether this image view should use a Metal texture view, // Determine whether this image view should use a Metal texture view,
// and set the _useMTLTextureView variable appropriately. // 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() { MVKImageViewPlane::~MVKImageViewPlane() {
[_mtlTexture release]; [_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() { MVKImageView::~MVKImageView() {
mvkDestroyContainerContents(_planes); mvkDestroyContainerContents(_planes);
} }