From dc917c80736715ac271471289f04654f1d578158 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Sun, 7 Apr 2019 22:40:30 +0200 Subject: [PATCH] radv: Allow mixed src/dst aspects in copies. e.g. COLOR + PLANE_2, as well COLOR + COLOR for multiplane images. Reviewed-by: Samuel Pitoiset --- src/amd/vulkan/radv_meta_copy.c | 220 +++++++++++++++++++++------------------- 1 file changed, 116 insertions(+), 104 deletions(-) diff --git a/src/amd/vulkan/radv_meta_copy.c b/src/amd/vulkan/radv_meta_copy.c index 1736f05..8081057 100644 --- a/src/amd/vulkan/radv_meta_copy.c +++ b/src/amd/vulkan/radv_meta_copy.c @@ -82,9 +82,10 @@ vk_format_for_size(int bs) static struct radv_meta_blit2d_surf blit_surf_for_image_level_layer(struct radv_image *image, VkImageLayout layout, - const VkImageSubresourceLayers *subres) + const VkImageSubresourceLayers *subres, + VkImageAspectFlags aspect_mask) { - VkFormat format = radv_get_aspect_format(image, subres->aspectMask); + VkFormat format = radv_get_aspect_format(image, aspect_mask); if (!radv_image_has_dcc(image) && !(radv_image_is_tc_compat_htile(image))) @@ -98,7 +99,7 @@ blit_surf_for_image_level_layer(struct radv_image *image, .level = subres->mipLevel, .layer = subres->baseArrayLayer, .image = image, - .aspect_mask = subres->aspectMask, + .aspect_mask = aspect_mask, .current_layout = layout, }; } @@ -183,7 +184,8 @@ meta_copy_buffer_to_image(struct radv_cmd_buffer *cmd_buffer, struct radv_meta_blit2d_surf img_bsurf = blit_surf_for_image_level_layer(image, layout, - &pRegions[r].imageSubresource); + &pRegions[r].imageSubresource, + pRegions[r].imageSubresource.aspectMask); struct radv_meta_blit2d_buffer buf_bsurf = { .bs = img_bsurf.bs, @@ -308,7 +310,8 @@ meta_copy_image_to_buffer(struct radv_cmd_buffer *cmd_buffer, struct radv_meta_blit2d_surf img_info = blit_surf_for_image_level_layer(image, layout, - &pRegions[r].imageSubresource); + &pRegions[r].imageSubresource, + pRegions[r].imageSubresource.aspectMask); struct radv_meta_blit2d_buffer buf_info = { .bs = img_info.bs, @@ -400,111 +403,120 @@ meta_copy_image(struct radv_cmd_buffer *cmd_buffer, cmd_buffer->state.predicating = false; for (unsigned r = 0; r < regionCount; r++) { - assert(pRegions[r].srcSubresource.aspectMask == - pRegions[r].dstSubresource.aspectMask); - - /* Create blit surfaces */ - struct radv_meta_blit2d_surf b_src = - blit_surf_for_image_level_layer(src_image, - src_image_layout, - &pRegions[r].srcSubresource); - - struct radv_meta_blit2d_surf b_dst = - blit_surf_for_image_level_layer(dest_image, - dest_image_layout, - &pRegions[r].dstSubresource); - - uint32_t dst_queue_mask = radv_image_queue_family_mask(dest_image, - cmd_buffer->queue_family_index, - cmd_buffer->queue_family_index); - bool dst_compressed = radv_layout_dcc_compressed(dest_image, dest_image_layout, dst_queue_mask); - uint32_t src_queue_mask = radv_image_queue_family_mask(src_image, - cmd_buffer->queue_family_index, - cmd_buffer->queue_family_index); - bool src_compressed = radv_layout_dcc_compressed(src_image, src_image_layout, src_queue_mask); - - if (!src_compressed || radv_dcc_formats_compatible(b_src.format, b_dst.format)) { - b_src.format = b_dst.format; - } else if (!dst_compressed) { - b_dst.format = b_src.format; - } else { - radv_decompress_dcc(cmd_buffer, dest_image, &(VkImageSubresourceRange) { - .aspectMask = pRegions[r].dstSubresource.aspectMask, - .baseMipLevel = pRegions[r].dstSubresource.mipLevel, - .levelCount = 1, - .baseArrayLayer = pRegions[r].dstSubresource.baseArrayLayer, - .layerCount = pRegions[r].dstSubresource.layerCount, - }); - b_dst.format = b_src.format; - b_dst.current_layout = VK_IMAGE_LAYOUT_GENERAL; - } - - - /** - * From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images - * imageExtent is the size in texels of the image to copy in width, height - * and depth. 1D images use only x and width. 2D images use x, y, width - * and height. 3D images use x, y, z, width, height and depth. - * - * Also, convert the offsets and extent from units of texels to units of - * blocks - which is the highest resolution accessible in this command. - */ - const VkOffset3D dst_offset_el = - meta_region_offset_el(dest_image, &pRegions[r].dstOffset); - const VkOffset3D src_offset_el = - meta_region_offset_el(src_image, &pRegions[r].srcOffset); - - /* - * From Vulkan 1.0.68, "Copying Data Between Images": - * "When copying between compressed and uncompressed formats - * the extent members represent the texel dimensions of the - * source image and not the destination." - * However, we must use the destination image type to avoid - * clamping depth when copying multiple layers of a 2D image to - * a 3D image. - */ - const VkExtent3D img_extent_el = - meta_region_extent_el(src_image, dest_image->type, &pRegions[r].extent); - - /* Start creating blit rect */ - struct radv_meta_blit2d_rect rect = { - .width = img_extent_el.width, - .height = img_extent_el.height, - }; - - if (src_image->type == VK_IMAGE_TYPE_3D) - b_src.layer = src_offset_el.z; + VkImageAspectFlags src_aspects[3] = {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT}; + VkImageAspectFlags dst_aspects[3] = {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT}; + unsigned aspect_count = pRegions[r].srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT ? src_image->plane_count : 1; + if (pRegions[r].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) + src_aspects[0] = pRegions[r].srcSubresource.aspectMask; + if (pRegions[r].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) + dst_aspects[0] = pRegions[r].dstSubresource.aspectMask; + + for (unsigned a = 0; a < aspect_count; ++a) { + /* Create blit surfaces */ + struct radv_meta_blit2d_surf b_src = + blit_surf_for_image_level_layer(src_image, + src_image_layout, + &pRegions[r].srcSubresource, + src_aspects[a]); + + struct radv_meta_blit2d_surf b_dst = + blit_surf_for_image_level_layer(dest_image, + dest_image_layout, + &pRegions[r].dstSubresource, + dst_aspects[a]); + + uint32_t dst_queue_mask = radv_image_queue_family_mask(dest_image, + cmd_buffer->queue_family_index, + cmd_buffer->queue_family_index); + bool dst_compressed = radv_layout_dcc_compressed(dest_image, dest_image_layout, dst_queue_mask); + uint32_t src_queue_mask = radv_image_queue_family_mask(src_image, + cmd_buffer->queue_family_index, + cmd_buffer->queue_family_index); + bool src_compressed = radv_layout_dcc_compressed(src_image, src_image_layout, src_queue_mask); + + if (!src_compressed || radv_dcc_formats_compatible(b_src.format, b_dst.format)) { + b_src.format = b_dst.format; + } else if (!dst_compressed) { + b_dst.format = b_src.format; + } else { + radv_decompress_dcc(cmd_buffer, dest_image, &(VkImageSubresourceRange) { + .aspectMask = dst_aspects[a], + .baseMipLevel = pRegions[r].dstSubresource.mipLevel, + .levelCount = 1, + .baseArrayLayer = pRegions[r].dstSubresource.baseArrayLayer, + .layerCount = pRegions[r].dstSubresource.layerCount, + }); + b_dst.format = b_src.format; + b_dst.current_layout = VK_IMAGE_LAYOUT_GENERAL; + } - if (dest_image->type == VK_IMAGE_TYPE_3D) - b_dst.layer = dst_offset_el.z; - /* Loop through each 3D or array slice */ - unsigned num_slices_3d = img_extent_el.depth; - unsigned num_slices_array = pRegions[r].dstSubresource.layerCount; - unsigned slice_3d = 0; - unsigned slice_array = 0; - while (slice_3d < num_slices_3d && slice_array < num_slices_array) { + /** + * From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images + * imageExtent is the size in texels of the image to copy in width, height + * and depth. 1D images use only x and width. 2D images use x, y, width + * and height. 3D images use x, y, z, width, height and depth. + * + * Also, convert the offsets and extent from units of texels to units of + * blocks - which is the highest resolution accessible in this command. + */ + const VkOffset3D dst_offset_el = + meta_region_offset_el(dest_image, &pRegions[r].dstOffset); + const VkOffset3D src_offset_el = + meta_region_offset_el(src_image, &pRegions[r].srcOffset); + + /* + * From Vulkan 1.0.68, "Copying Data Between Images": + * "When copying between compressed and uncompressed formats + * the extent members represent the texel dimensions of the + * source image and not the destination." + * However, we must use the destination image type to avoid + * clamping depth when copying multiple layers of a 2D image to + * a 3D image. + */ + const VkExtent3D img_extent_el = + meta_region_extent_el(src_image, dest_image->type, &pRegions[r].extent); - /* Finish creating blit rect */ - rect.dst_x = dst_offset_el.x; - rect.dst_y = dst_offset_el.y; - rect.src_x = src_offset_el.x; - rect.src_y = src_offset_el.y; + /* Start creating blit rect */ + struct radv_meta_blit2d_rect rect = { + .width = img_extent_el.width, + .height = img_extent_el.height, + }; - /* Perform Blit */ - if (cs || - !image_is_renderable(cmd_buffer->device, b_dst.image)) { - radv_meta_image_to_image_cs(cmd_buffer, &b_src, &b_dst, 1, &rect); - } else { - radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect); - } + if (src_image->type == VK_IMAGE_TYPE_3D) + b_src.layer = src_offset_el.z; - b_src.layer++; - b_dst.layer++; if (dest_image->type == VK_IMAGE_TYPE_3D) - slice_3d++; - else - slice_array++; + b_dst.layer = dst_offset_el.z; + + /* Loop through each 3D or array slice */ + unsigned num_slices_3d = img_extent_el.depth; + unsigned num_slices_array = pRegions[r].dstSubresource.layerCount; + unsigned slice_3d = 0; + unsigned slice_array = 0; + while (slice_3d < num_slices_3d && slice_array < num_slices_array) { + + /* Finish creating blit rect */ + rect.dst_x = dst_offset_el.x; + rect.dst_y = dst_offset_el.y; + rect.src_x = src_offset_el.x; + rect.src_y = src_offset_el.y; + + /* Perform Blit */ + if (cs || + !image_is_renderable(cmd_buffer->device, b_dst.image)) { + radv_meta_image_to_image_cs(cmd_buffer, &b_src, &b_dst, 1, &rect); + } else { + radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect); + } + + b_src.layer++; + b_dst.layer++; + if (dest_image->type == VK_IMAGE_TYPE_3D) + slice_3d++; + else + slice_array++; + } } } -- 2.7.4