diff options
| author | Dave Houlton <daveh@lunarg.com> | 2018-03-06 11:08:51 -0700 |
|---|---|---|
| committer | Dave Houlton <daveh@lunarg.com> | 2018-04-04 13:55:41 -0600 |
| commit | eca2e760c028a19e2396168af71a98cfee7de7f1 (patch) | |
| tree | d5cf58feeca6d1af6f7fc8d7624f736f3be06570 | |
| parent | 12e5bbe47c1ac46cb1f1f422bc9379c0724cf27a (diff) | |
| download | usermoji-eca2e760c028a19e2396168af71a98cfee7de7f1.tar.xz | |
layers: add multiplane image formats and checks
Add support for new formats added by sampler_YCbCr and mainlined in
Vulkan 1.1. Adds single- and multi-plane formats to lookup utility
fxns. Adds checks for CmdCopyImage VUIDS that were added or modified.
Change-Id: I70279bd8d667bf50d53fce752b53bb7e2e0a2d67
| -rw-r--r-- | layers/buffer_validation.cpp | 148 | ||||
| -rw-r--r-- | layers/vk_format_utils.cpp | 159 | ||||
| -rw-r--r-- | layers/vk_format_utils.h | 37 |
3 files changed, 309 insertions, 35 deletions
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp index 9abc47b3..1dfa2210 100644 --- a/layers/buffer_validation.cpp +++ b/layers/buffer_validation.cpp @@ -1213,27 +1213,29 @@ static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, u return result; } -// Returns true if two VkImageCopy structures overlap -static bool RegionIntersects(const VkImageCopy *src, const VkImageCopy *dst, VkImageType type, bool is_multiplane) { +// Returns true if source area of first copy region intersects dest area of second region +// It is assumed that these are copy regions within a single image (otherwise no possibility of collision) +static bool RegionIntersects(const VkImageCopy *rgn0, const VkImageCopy *rgn1, VkImageType type, bool is_multiplane) { bool result = false; - if (is_multiplane && (src->srcSubresource.aspectMask != dst->dstSubresource.aspectMask)) { + // Separate planes within a multiplane image cannot intersect + if (is_multiplane && (rgn0->srcSubresource.aspectMask != rgn1->dstSubresource.aspectMask)) { return result; } - if ((src->srcSubresource.mipLevel == dst->dstSubresource.mipLevel) && - (RangesIntersect(src->srcSubresource.baseArrayLayer, src->srcSubresource.layerCount, dst->dstSubresource.baseArrayLayer, - dst->dstSubresource.layerCount))) { + if ((rgn0->srcSubresource.mipLevel == rgn1->dstSubresource.mipLevel) && + (RangesIntersect(rgn0->srcSubresource.baseArrayLayer, rgn0->srcSubresource.layerCount, rgn1->dstSubresource.baseArrayLayer, + rgn1->dstSubresource.layerCount))) { result = true; switch (type) { case VK_IMAGE_TYPE_3D: - result &= RangesIntersect(src->srcOffset.z, src->extent.depth, dst->dstOffset.z, dst->extent.depth); + result &= RangesIntersect(rgn0->srcOffset.z, rgn0->extent.depth, rgn1->dstOffset.z, rgn1->extent.depth); // Intentionally fall through to 2D case case VK_IMAGE_TYPE_2D: - result &= RangesIntersect(src->srcOffset.y, src->extent.height, dst->dstOffset.y, dst->extent.height); + result &= RangesIntersect(rgn0->srcOffset.y, rgn0->extent.height, rgn1->dstOffset.y, rgn1->extent.height); // Intentionally fall through to 1D case case VK_IMAGE_TYPE_1D: - result &= RangesIntersect(src->srcOffset.x, src->extent.width, dst->dstOffset.x, dst->extent.width); + result &= RangesIntersect(rgn0->srcOffset.x, rgn0->extent.width, rgn1->dstOffset.x, rgn1->extent.width); break; default: // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation @@ -1577,51 +1579,56 @@ bool ValidateImageCopyData(const layer_data *device_data, const debug_report_dat } } - // Checks that apply only to compressed images - if (FormatIsCompressed(src_state->createInfo.format)) { + // Source checks that apply only to compressed images (or to _422 images if ycbcr enabled) + bool ext_ycbcr = GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion; + if (FormatIsCompressed(src_state->createInfo.format) || + (ext_ycbcr && FormatIsSinglePlane_422(src_state->createInfo.format))) { const VkExtent3D block_size = FormatCompressedTexelBlockExtent(src_state->createInfo.format); - // image offsets must be multiples of block dimensions if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) || (SafeModulo(region.srcOffset.y, block_size.height) != 0) || (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d7e : VALIDATION_ERROR_09c0013a; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(src_state->image), VALIDATION_ERROR_09c0013a, + HandleToUint64(src_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] srcOffset (%d, %d) must be multiples of the compressed image's " - "texel width & height (%d, %d)..", + "texel width & height (%d, %d).", i, region.srcOffset.x, region.srcOffset.y, block_size.width, block_size.height); } const VkExtent3D mip_extent = GetImageSubresourceExtent(src_state, &(region.srcSubresource)); if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) && (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d80 : VALIDATION_ERROR_09c0013c; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(src_state->image), VALIDATION_ERROR_09c0013c, + HandleToUint64(src_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block " - "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d)..", + "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d).", i, src_copy_extent.width, block_size.width, region.srcOffset.x, mip_extent.width); } // Extent height must be a multiple of block height, or extent+offset height must equal subresource height if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) && (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d82 : VALIDATION_ERROR_09c0013e; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(src_state->image), VALIDATION_ERROR_09c0013e, + HandleToUint64(src_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] extent height (%d) must be a multiple of the compressed texture block " - "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d)..", + "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d).", i, src_copy_extent.height, block_size.height, region.srcOffset.y, mip_extent.height); } // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth); if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d84 : VALIDATION_ERROR_09c00140; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(src_state->image), VALIDATION_ERROR_09c00140, + HandleToUint64(src_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block " - "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d)..", + "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d).", i, src_copy_extent.depth, block_size.depth, region.srcOffset.z, mip_extent.depth); } } // Compressed @@ -1689,51 +1696,56 @@ bool ValidateImageCopyData(const layer_data *device_data, const debug_report_dat } } - // Checks that apply only to compressed images - if (FormatIsCompressed(dst_state->createInfo.format)) { + // Dest checks that apply only to compressed images (or to _422 images if ycbcr enabled) + if (FormatIsCompressed(dst_state->createInfo.format) || + (ext_ycbcr && FormatIsSinglePlane_422(dst_state->createInfo.format))) { const VkExtent3D block_size = FormatCompressedTexelBlockExtent(dst_state->createInfo.format); // image offsets must be multiples of block dimensions if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) || (SafeModulo(region.dstOffset.y, block_size.height) != 0) || (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d86 : VALIDATION_ERROR_09c00144; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(dst_state->image), VALIDATION_ERROR_09c00144, + HandleToUint64(dst_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] dstOffset (%d, %d) must be multiples of the compressed image's " - "texel width & height (%d, %d)..", + "texel width & height (%d, %d).", i, region.dstOffset.x, region.dstOffset.y, block_size.width, block_size.height); } const VkExtent3D mip_extent = GetImageSubresourceExtent(dst_state, &(region.dstSubresource)); if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) && (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d88 : VALIDATION_ERROR_09c00146; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(dst_state->image), VALIDATION_ERROR_09c00146, + HandleToUint64(dst_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture " - "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d)..", + "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d).", i, dst_copy_extent.width, block_size.width, region.dstOffset.x, mip_extent.width); } // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) && (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d8a : VALIDATION_ERROR_09c00148; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(dst_state->image), VALIDATION_ERROR_09c00148, + HandleToUint64(dst_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed " "texture block height (%d), or when added to dstOffset.y (%d) must equal the image subresource " - "height (%d)..", + "height (%d).", i, dst_copy_extent.height, block_size.height, region.dstOffset.y, mip_extent.height); } // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth); if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) { + UNIQUE_VALIDATION_ERROR_CODE vuid = ext_ycbcr ? VALIDATION_ERROR_09c00d8c : VALIDATION_ERROR_09c0014a; skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(dst_state->image), VALIDATION_ERROR_09c0014a, + HandleToUint64(dst_state->image), vuid, "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture " - "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d)..", + "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d).", i, dst_copy_extent.depth, block_size.depth, region.dstOffset.z, mip_extent.depth); } } // Compressed @@ -1741,6 +1753,77 @@ bool ValidateImageCopyData(const layer_data *device_data, const debug_report_dat return skip; } +// vkCmdCopyImage checks that only apply if the multiplane extension is enabled +bool CopyImageMultiplaneValidation(const layer_data *dev_data, VkCommandBuffer command_buffer, const IMAGE_STATE *src_image_state, + const IMAGE_STATE *dst_image_state, const VkImageCopy region) { + bool skip = false; + const debug_report_data *report_data = core_validation::GetReportData(dev_data); + + // Neither image is multiplane + if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format))) { + // If neither image is multi-plane the aspectMask member of src and dst must match + if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) { + std::stringstream ss; + ss << "vkCmdCopyImage: Copy between non-multiplane images with differing aspectMasks ( 0x" << std::hex + << region.srcSubresource.aspectMask << " and 0x" << region.dstSubresource.aspectMask << " )"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c1e, "%s.", ss.str().c_str()); + } + } else { + // Source image multiplane checks + uint32_t planes = FormatPlaneCount(src_image_state->createInfo.format); + VkImageAspectFlags aspect = region.srcSubresource.aspectMask; + if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c20, "%s.", ss.str().c_str()); + } + if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) && + (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c22, "%s.", ss.str().c_str()); + } + // Single-plane to multi-plane + if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (FormatIsMultiplane(dst_image_state->createInfo.format)) && + (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c2a, "%s.", ss.str().c_str()); + } + + // Dest image multiplane checks + planes = FormatPlaneCount(dst_image_state->createInfo.format); + aspect = region.dstSubresource.aspectMask; + if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c24, "%s.", ss.str().c_str()); + } + if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) && + (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c26, "%s.", ss.str().c_str()); + } + // Multi-plane to single-plane + if ((FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format)) && + (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) { + std::stringstream ss; + ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + HandleToUint64(command_buffer), VALIDATION_ERROR_09c00c28, "%s.", ss.str().c_str()); + } + } + + return skip; +} + bool PreCallValidateCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state, IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions, VkImageLayout src_image_layout, VkImageLayout dst_image_layout) { @@ -1817,6 +1900,11 @@ bool PreCallValidateCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_nod } } + // Do multiplane-specific checks, if extension enabled + if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) { + skip |= CopyImageMultiplaneValidation(device_data, command_buffer, src_image_state, dst_image_state, region); + } + if (!GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) { // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) { diff --git a/layers/vk_format_utils.cpp b/layers/vk_format_utils.cpp index 83029fe7..9784dd5a 100644 --- a/layers/vk_format_utils.cpp +++ b/layers/vk_format_utils.cpp @@ -229,7 +229,40 @@ const std::map<VkFormat, VULKAN_FORMAT_INFO> vk_format_table = { {VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC1_2BPP_BIT}}, {VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC1_4BPP_BIT}}, {VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_2BPP_BIT}}, - {VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_4BPP_BIT}} + {VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_4BPP_BIT}}, + /* KHR_sampler_YCbCr_conversion */ + {VK_FORMAT_G8B8G8R8_422_UNORM_KHR, {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_G8B8G8R8}}, + {VK_FORMAT_B8G8R8G8_422_UNORM_KHR, {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_B8G8R8G8}}, + {VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R10G10B10A10}}, + {VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G10B10G10R10}}, + {VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B10G10R10G10}}, + {VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R12G12B12A12}}, + {VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G12B12G12R12}}, + {VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B12G12R12G12}}, + {VK_FORMAT_G16B16G16R16_422_UNORM_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G16B16G16R16}}, + {VK_FORMAT_B16G16R16G16_422_UNORM_KHR, {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B16G16R16G16}}, +#if 0 // TBD - Figure out what size means for multi-planar formats + {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_420}}, + {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_420}}, + {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_422}}, + {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_422}}, + {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_444}}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_420}}, + {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_420}}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_422}}, + {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_422}}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_444}}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_420}}, + {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_420}}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_422}}, + {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_422}}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_444}}, + {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_420}}, + {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_420}}, + {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_422}}, + {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_422}}, + {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR, {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_444}} +#endif }; // Renable formatting @@ -349,6 +382,27 @@ VK_LAYER_EXPORT bool FormatIsCompressed_PVRTC(VkFormat format) { return found; } +// Single-plane "_422" formats are treated as 2x1 compressed (for copies) +VK_LAYER_EXPORT bool FormatIsSinglePlane_422(VkFormat format) { + bool found = false; + + switch (format) { + case VK_FORMAT_G8B8G8R8_422_UNORM_KHR: + case VK_FORMAT_B8G8R8G8_422_UNORM_KHR: + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR: + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR: + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR: + case VK_FORMAT_G16B16G16R16_422_UNORM_KHR: + case VK_FORMAT_B16G16R16G16_422_UNORM_KHR: + found = true; + break; + default: + break; + } + return found; +} + // Return true if format is compressed VK_LAYER_EXPORT bool FormatIsCompressed(VkFormat format) { return (FormatIsCompressed_ASTC_LDR(format) || FormatIsCompressed_BC(format) || FormatIsCompressed_ETC2_EAC(format) || @@ -858,6 +912,18 @@ VK_LAYER_EXPORT VkExtent3D FormatCompressedTexelBlockExtent(VkFormat format) { case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: block_size = {4, 4, 1}; break; + // With KHR_sampler_ycbcr_conversion, these formats are treated as 2x1 compressed (for copies) + case VK_FORMAT_G8B8G8R8_422_UNORM_KHR: + case VK_FORMAT_B8G8R8G8_422_UNORM_KHR: + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR: + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR: + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR: + case VK_FORMAT_G16B16G16R16_422_UNORM_KHR: + case VK_FORMAT_B16G16R16G16_422_UNORM_KHR: + block_size = {2, 1, 1}; + break; + default: break; } @@ -878,7 +944,7 @@ VK_LAYER_EXPORT uint32_t FormatPlaneCount(VkFormat format) { case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR: case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR: case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR: - return 3u; + return 3; break; case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR: case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR: @@ -888,10 +954,10 @@ VK_LAYER_EXPORT uint32_t FormatPlaneCount(VkFormat format) { case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR: case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR: case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR: - return 2u; + return 2; break; default: - return 1u; + return 1; break; } } @@ -931,3 +997,88 @@ VK_LAYER_EXPORT VkDeviceSize SafeModulo(VkDeviceSize dividend, VkDeviceSize divi } return result; } + +struct VULKAN_PER_PLANE_COMPATIBILITY { + uint32_t width_divisor; + uint32_t height_divisor; + VkFormat compatible_format; +}; + +struct VULKAN_MULTIPLANE_COMPATIBILITY { + VULKAN_PER_PLANE_COMPATIBILITY per_plane[VK_MULTIPLANE_FORMAT_MAX_PLANES]; +}; + +// Source: Vulkan spec Table 45. Plane Format Compatibility Table +// clang-format off +const std::map<VkFormat, VULKAN_MULTIPLANE_COMPATIBILITY> vk_multiplane_compatibility_map { + { VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR, { { { 1, 1, VK_FORMAT_R8_UNORM }, + { 2, 2, VK_FORMAT_R8_UNORM }, + { 2, 2, VK_FORMAT_R8_UNORM } } } }, + { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR, { { { 1, 1, VK_FORMAT_R8_UNORM }, + { 2, 2, VK_FORMAT_R8G8_UNORM }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR, { { { 1, 1, VK_FORMAT_R8_UNORM }, + { 2, 1, VK_FORMAT_R8_UNORM }, + { 2, 1, VK_FORMAT_R8_UNORM } } } }, + { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR, { { { 1, 1, VK_FORMAT_R8_UNORM }, + { 2, 1, VK_FORMAT_R8G8_UNORM }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR, { { { 1, 1, VK_FORMAT_R8_UNORM }, + { 1, 1, VK_FORMAT_R8_UNORM }, + { 1, 1, VK_FORMAT_R8_UNORM } } } }, + { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR }, + { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 2, VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 2, 1, VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR }, + { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } }, + { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR, { { { 1, 1, VK_FORMAT_R16_UNORM }, + { 2, 2, VK_FORMAT_R16_UNORM }, + { 2, 2, VK_FORMAT_R16_UNORM } } } }, + { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR, { { { 1, 1, VK_FORMAT_R16_UNORM }, + { 2, 2, VK_FORMAT_R16G16_UNORM }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR, { { { 1, 1, VK_FORMAT_R16_UNORM }, + { 2, 1, VK_FORMAT_R16_UNORM }, + { 2, 1, VK_FORMAT_R16_UNORM } } } }, + { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR, { { { 1, 1, VK_FORMAT_R16_UNORM }, + { 2, 1, VK_FORMAT_R16G16_UNORM }, + { 1, 1, VK_FORMAT_UNDEFINED } } } }, + { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR, { { { 1, 1, VK_FORMAT_R16_UNORM }, + { 1, 1, VK_FORMAT_R16_UNORM }, + { 1, 1, VK_FORMAT_R16_UNORM } } } } +}; +// clang-format on + +VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat mp_fmt, uint32_t plane) { + auto it = vk_multiplane_compatibility_map.find(mp_fmt); + if ((it == vk_multiplane_compatibility_map.end()) || (plane >= VK_MULTIPLANE_FORMAT_MAX_PLANES)) { + return VK_FORMAT_UNDEFINED; + } + + return it->second.per_plane[plane].compatible_format; +} diff --git a/layers/vk_format_utils.h b/layers/vk_format_utils.h index c5304059..e76f9ec2 100644 --- a/layers/vk_format_utils.h +++ b/layers/vk_format_utils.h @@ -38,6 +38,8 @@ extern "C" { #endif +#define VK_MULTIPLANE_FORMAT_MAX_PLANES 3 + typedef enum VkFormatCompatibilityClass { VK_FORMAT_COMPATIBILITY_CLASS_NONE_BIT = 0, VK_FORMAT_COMPATIBILITY_CLASS_8_BIT = 1, @@ -88,7 +90,38 @@ typedef enum VkFormatCompatibilityClass { VK_FORMAT_COMPATIBILITY_CLASS_PVRTC1_4BPP_BIT = 46, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_2BPP_BIT = 47, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_4BPP_BIT = 48, - VK_FORMAT_COMPATIBILITY_CLASS_MAX_ENUM = 49 + /* KHR_sampler_YCbCr_conversion */ + VK_FORMAT_COMPATIBILITY_CLASS_32BIT_G8B8G8R8 = 49, + VK_FORMAT_COMPATIBILITY_CLASS_32BIT_B8G8R8G8 = 50, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R10G10B10A10 = 51, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G10B10G10R10 = 52, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B10G10R10G10 = 53, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R12G12B12A12 = 54, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G12B12G12R12 = 55, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B12G12R12G12 = 56, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G16B16G16R16 = 57, + VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B16G16R16G16 = 58, + VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_420 = 59, + VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_420 = 60, + VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_422 = 61, + VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_422 = 62, + VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_444 = 63, + VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_420 = 64, + VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_420 = 65, + VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_422 = 66, + VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_422 = 67, + VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_444 = 68, + VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_420 = 69, + VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_420 = 70, + VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_422 = 71, + VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_422 = 72, + VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_444 = 73, + VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_420 = 74, + VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_420 = 75, + VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_422 = 76, + VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_422 = 77, + VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_444 = 78, + VK_FORMAT_COMPATIBILITY_CLASS_MAX_ENUM = 79 } VkFormatCompatibilityClass; VK_LAYER_EXPORT bool FormatIsDepthOrStencil(VkFormat format); @@ -99,6 +132,7 @@ VK_LAYER_EXPORT bool FormatIsCompressed_ETC2_EAC(VkFormat format); VK_LAYER_EXPORT bool FormatIsCompressed_ASTC_LDR(VkFormat format); VK_LAYER_EXPORT bool FormatIsCompressed_BC(VkFormat format); VK_LAYER_EXPORT bool FormatIsCompressed_PVRTC(VkFormat format); +VK_LAYER_EXPORT bool FormatIsSinglePlane_422(VkFormat format); VK_LAYER_EXPORT bool FormatIsNorm(VkFormat format); VK_LAYER_EXPORT bool FormatIsUNorm(VkFormat format); VK_LAYER_EXPORT bool FormatIsSNorm(VkFormat format); @@ -117,6 +151,7 @@ VK_LAYER_EXPORT VkExtent3D FormatCompressedTexelBlockExtent(VkFormat format); VK_LAYER_EXPORT size_t FormatSize(VkFormat format); VK_LAYER_EXPORT VkFormatCompatibilityClass FormatCompatibilityClass(VkFormat format); VK_LAYER_EXPORT VkDeviceSize SafeModulo(VkDeviceSize dividend, VkDeviceSize divisor); +VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat fmt, uint32_t plane); static inline bool FormatIsUndef(VkFormat format) { return (format == VK_FORMAT_UNDEFINED); } static inline bool FormatHasDepth(VkFormat format) { return (FormatIsDepthOnly(format) || FormatIsDepthAndStencil(format)); } |
