diff --git a/src/amd/vulkan/radv_formats.c b/src/amd/vulkan/radv_formats.c index ce2d81df10f..1ad9ca19876 100644 --- a/src/amd/vulkan/radv_formats.c +++ b/src/amd/vulkan/radv_formats.c @@ -1263,8 +1263,11 @@ radv_check_modifier_support(struct radv_physical_device *dev, if (!found) return VK_ERROR_FORMAT_NOT_SUPPORTED; + bool need_dcc_sign_reinterpret = false; if (ac_modifier_has_dcc(modifier) && - !radv_are_formats_dcc_compatible(dev, info->pNext, format, info->flags)) + !radv_are_formats_dcc_compatible(dev, info->pNext, format, info->flags, + &need_dcc_sign_reinterpret) && + !need_dcc_sign_reinterpret) return VK_ERROR_FORMAT_NOT_SUPPORTED; /* We can expand this as needed and implemented but there is not much demand @@ -1903,21 +1906,16 @@ radv_GetPhysicalDeviceExternalBufferProperties( /* DCC channel type categories within which formats can be reinterpreted * while keeping the same DCC encoding. The swizzle must also match. */ enum dcc_channel_type { - dcc_channel_float32, - dcc_channel_uint32, - dcc_channel_sint32, - dcc_channel_float16, - dcc_channel_uint16, - dcc_channel_sint16, - dcc_channel_uint_10_10_10_2, - dcc_channel_uint8, - dcc_channel_sint8, + dcc_channel_float, + dcc_channel_uint, + dcc_channel_sint, dcc_channel_incompatible, }; /* Return the type of DCC encoding. */ -static enum dcc_channel_type -radv_get_dcc_channel_type(const struct util_format_description *desc) +static void +radv_get_dcc_channel_type(const struct util_format_description *desc, enum dcc_channel_type *type, + unsigned *size) { int i; @@ -1925,39 +1923,37 @@ radv_get_dcc_channel_type(const struct util_format_description *desc) for (i = 0; i < desc->nr_channels; i++) if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) break; - if (i == desc->nr_channels) - return dcc_channel_incompatible; + if (i == desc->nr_channels) { + *type = dcc_channel_incompatible; + return; + } switch (desc->channel[i].size) { case 32: - if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) - return dcc_channel_float32; - if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) - return dcc_channel_uint32; - return dcc_channel_sint32; case 16: - if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) - return dcc_channel_float16; - if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) - return dcc_channel_uint16; - return dcc_channel_sint16; case 10: - return dcc_channel_uint_10_10_10_2; case 8: - if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) - return dcc_channel_uint8; - return dcc_channel_sint8; + *size = desc->channel[i].size; + if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) + *type = dcc_channel_float; + else if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) + *type = dcc_channel_uint; + else + *type = dcc_channel_sint; + break; default: - return dcc_channel_incompatible; + *type = dcc_channel_incompatible; + break; } } /* Return if it's allowed to reinterpret one format as another with DCC enabled. */ bool -radv_dcc_formats_compatible(VkFormat format1, VkFormat format2) +radv_dcc_formats_compatible(VkFormat format1, VkFormat format2, bool *sign_reinterpret) { const struct util_format_description *desc1, *desc2; enum dcc_channel_type type1, type2; + unsigned size1, size2; int i; if (format1 == format2) @@ -1975,8 +1971,15 @@ radv_dcc_formats_compatible(VkFormat format1, VkFormat format2) desc1->swizzle[i] != desc2->swizzle[i]) return false; - type1 = radv_get_dcc_channel_type(desc1); - type2 = radv_get_dcc_channel_type(desc2); + radv_get_dcc_channel_type(desc1, &type1, &size1); + radv_get_dcc_channel_type(desc2, &type2, &size2); - return type1 != dcc_channel_incompatible && type2 != dcc_channel_incompatible && type1 == type2; + if (type1 == dcc_channel_incompatible || type2 == dcc_channel_incompatible || + (type1 == dcc_channel_float) != (type2 == dcc_channel_float) || size1 != size2) + return false; + + if (type1 != type2) + *sign_reinterpret = true; + + return true; } diff --git a/src/amd/vulkan/radv_image.c b/src/amd/vulkan/radv_image.c index 32cef33f2d9..45b5f53725a 100644 --- a/src/amd/vulkan/radv_image.c +++ b/src/amd/vulkan/radv_image.c @@ -150,13 +150,16 @@ radv_image_use_fast_clear_for_image(const struct radv_device *device, bool radv_are_formats_dcc_compatible(const struct radv_physical_device *pdev, const void *pNext, - VkFormat format, VkImageCreateFlags flags) + VkFormat format, VkImageCreateFlags flags, bool *sign_reinterpret) { bool blendable; if (!radv_is_colorbuffer_format_supported(pdev, format, &blendable)) return false; + if (sign_reinterpret != NULL) + *sign_reinterpret = false; + if (flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { const struct VkImageFormatListCreateInfo *format_list = (const struct VkImageFormatListCreateInfo *)vk_find_struct_const( @@ -170,7 +173,8 @@ radv_are_formats_dcc_compatible(const struct radv_physical_device *pdev, const v if (format_list->pViewFormats[i] == VK_FORMAT_UNDEFINED) continue; - if (!radv_dcc_formats_compatible(format, format_list->pViewFormats[i])) + if (!radv_dcc_formats_compatible(format, format_list->pViewFormats[i], + sign_reinterpret)) return false; } } else { @@ -205,8 +209,9 @@ radv_formats_is_atomic_allowed(const void *pNext, VkFormat format, VkImageCreate } static bool -radv_use_dcc_for_image(struct radv_device *device, const struct radv_image *image, - const VkImageCreateInfo *pCreateInfo, VkFormat format) +radv_use_dcc_for_image(struct radv_device *device, struct radv_image *image, + const VkImageCreateInfo *pCreateInfo, VkFormat format, + bool *sign_reinterpret) { /* DCC (Delta Color Compression) is only available for GFX8+. */ if (device->physical_device->rad_info.chip_class < GFX8) @@ -260,7 +265,7 @@ radv_use_dcc_for_image(struct radv_device *device, const struct radv_image *imag } return radv_are_formats_dcc_compatible(device->physical_device, pCreateInfo->pNext, format, - pCreateInfo->flags); + pCreateInfo->flags, sign_reinterpret); } /* @@ -480,9 +485,8 @@ radv_patch_image_from_extra_info(struct radv_device *device, struct radv_image * } static uint64_t -radv_get_surface_flags(struct radv_device *device, const struct radv_image *image, - unsigned plane_id, const VkImageCreateInfo *pCreateInfo, - VkFormat image_format) +radv_get_surface_flags(struct radv_device *device, struct radv_image *image, unsigned plane_id, + const VkImageCreateInfo *pCreateInfo, VkFormat image_format) { uint64_t flags; unsigned array_mode = radv_choose_tiling(device, pCreateInfo, image_format); @@ -538,7 +542,8 @@ radv_get_surface_flags(struct radv_device *device, const struct radv_image *imag vk_format_get_blocksizebits(image_format) == 128 && vk_format_is_compressed(image_format)) flags |= RADEON_SURF_NO_RENDER_TARGET; - if (!radv_use_dcc_for_image(device, image, pCreateInfo, image_format)) + if (!radv_use_dcc_for_image(device, image, pCreateInfo, image_format, + &image->dcc_sign_reinterpret)) flags |= RADEON_SURF_DISABLE_DCC; if (!radv_use_fmask_for_image(device, image)) diff --git a/src/amd/vulkan/radv_meta_clear.c b/src/amd/vulkan/radv_meta_clear.c index b7fd48d2b5c..82bb12b5365 100644 --- a/src/amd/vulkan/radv_meta_clear.c +++ b/src/amd/vulkan/radv_meta_clear.c @@ -1760,6 +1760,10 @@ vi_get_fast_clear_parameters(struct radv_device *device, const struct radv_image desc->swizzle[i] >= PIPE_SWIZZLE_X && desc->swizzle[i] <= PIPE_SWIZZLE_W) return; + /* Only DCC clear code 0000 is allowed for signed<->unsigned formats. */ + if ((main_value || extra_value) && iview->image->dcc_sign_reinterpret) + return; + *can_avoid_fast_clear_elim = true; if (main_value) { diff --git a/src/amd/vulkan/radv_meta_copy.c b/src/amd/vulkan/radv_meta_copy.c index 168ccfc074c..a50818d1ddb 100644 --- a/src/amd/vulkan/radv_meta_copy.c +++ b/src/amd/vulkan/radv_meta_copy.c @@ -434,8 +434,11 @@ copy_image(struct radv_cmd_buffer *cmd_buffer, struct radv_image *src_image, bool src_compressed = radv_layout_dcc_compressed(cmd_buffer->device, src_image, region->srcSubresource.mipLevel, src_image_layout, false, src_queue_mask); + bool need_dcc_sign_reinterpret = false; - if (!src_compressed || radv_dcc_formats_compatible(b_src.format, b_dst.format)) { + if (!src_compressed || + (radv_dcc_formats_compatible(b_src.format, b_dst.format, &need_dcc_sign_reinterpret) && + !need_dcc_sign_reinterpret)) { b_src.format = b_dst.format; } else if (!dst_compressed) { b_dst.format = b_src.format; diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index 06d76567892..3d20e23d388 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -1873,7 +1873,7 @@ bool radv_is_storage_image_format_supported(struct radv_physical_device *physica VkFormat format); bool radv_is_colorbuffer_format_supported(const struct radv_physical_device *pdevice, VkFormat format, bool *blendable); -bool radv_dcc_formats_compatible(VkFormat format1, VkFormat format2); +bool radv_dcc_formats_compatible(VkFormat format1, VkFormat format2, bool *sign_reinterpret); bool radv_is_atomic_format_supported(VkFormat format); bool radv_device_supports_etc(struct radv_physical_device *physical_device); @@ -1901,6 +1901,7 @@ struct radv_image { bool exclusive; bool shareable; bool l2_coherent; + bool dcc_sign_reinterpret; /* Set when bound */ struct radeon_winsys_bo *bo; @@ -2243,7 +2244,8 @@ VkResult radv_image_create(VkDevice _device, const struct radv_image_create_info const VkAllocationCallbacks *alloc, VkImage *pImage); bool radv_are_formats_dcc_compatible(const struct radv_physical_device *pdev, const void *pNext, - VkFormat format, VkImageCreateFlags flags); + VkFormat format, VkImageCreateFlags flags, + bool *sign_reinterpret); bool vi_alpha_is_on_msb(struct radv_device *device, VkFormat format);