1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2016 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "radv_meta.h" 25bf215546Sopenharmony_ci#include "vk_format.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_cistatic VkFormat 28bf215546Sopenharmony_civk_format_for_size(int bs) 29bf215546Sopenharmony_ci{ 30bf215546Sopenharmony_ci switch (bs) { 31bf215546Sopenharmony_ci case 1: 32bf215546Sopenharmony_ci return VK_FORMAT_R8_UINT; 33bf215546Sopenharmony_ci case 2: 34bf215546Sopenharmony_ci return VK_FORMAT_R8G8_UINT; 35bf215546Sopenharmony_ci case 4: 36bf215546Sopenharmony_ci return VK_FORMAT_R8G8B8A8_UINT; 37bf215546Sopenharmony_ci case 8: 38bf215546Sopenharmony_ci return VK_FORMAT_R16G16B16A16_UINT; 39bf215546Sopenharmony_ci case 12: 40bf215546Sopenharmony_ci return VK_FORMAT_R32G32B32_UINT; 41bf215546Sopenharmony_ci case 16: 42bf215546Sopenharmony_ci return VK_FORMAT_R32G32B32A32_UINT; 43bf215546Sopenharmony_ci default: 44bf215546Sopenharmony_ci unreachable("Invalid format block size"); 45bf215546Sopenharmony_ci } 46bf215546Sopenharmony_ci} 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic struct radv_meta_blit2d_surf 49bf215546Sopenharmony_ciblit_surf_for_image_level_layer(struct radv_image *image, VkImageLayout layout, 50bf215546Sopenharmony_ci const VkImageSubresourceLayers *subres, 51bf215546Sopenharmony_ci VkImageAspectFlags aspect_mask) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci VkFormat format = radv_get_aspect_format(image, aspect_mask); 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci if (!radv_dcc_enabled(image, subres->mipLevel) && !(radv_image_is_tc_compat_htile(image))) 56bf215546Sopenharmony_ci format = vk_format_for_size(vk_format_get_blocksize(format)); 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci format = vk_format_no_srgb(format); 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci return (struct radv_meta_blit2d_surf){ 61bf215546Sopenharmony_ci .format = format, 62bf215546Sopenharmony_ci .bs = vk_format_get_blocksize(format), 63bf215546Sopenharmony_ci .level = subres->mipLevel, 64bf215546Sopenharmony_ci .layer = subres->baseArrayLayer, 65bf215546Sopenharmony_ci .image = image, 66bf215546Sopenharmony_ci .aspect_mask = aspect_mask, 67bf215546Sopenharmony_ci .current_layout = layout, 68bf215546Sopenharmony_ci }; 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cibool 72bf215546Sopenharmony_ciradv_image_is_renderable(struct radv_device *device, struct radv_image *image) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci if (image->vk.format == VK_FORMAT_R32G32B32_UINT || 75bf215546Sopenharmony_ci image->vk.format == VK_FORMAT_R32G32B32_SINT || 76bf215546Sopenharmony_ci image->vk.format == VK_FORMAT_R32G32B32_SFLOAT) 77bf215546Sopenharmony_ci return false; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (device->physical_device->rad_info.gfx_level >= GFX9 && 80bf215546Sopenharmony_ci image->vk.image_type == VK_IMAGE_TYPE_3D && 81bf215546Sopenharmony_ci vk_format_get_blocksizebits(image->vk.format) == 128 && 82bf215546Sopenharmony_ci vk_format_is_compressed(image->vk.format)) 83bf215546Sopenharmony_ci return false; 84bf215546Sopenharmony_ci return true; 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_cistatic void 88bf215546Sopenharmony_cicopy_buffer_to_image(struct radv_cmd_buffer *cmd_buffer, struct radv_buffer *buffer, 89bf215546Sopenharmony_ci struct radv_image *image, VkImageLayout layout, 90bf215546Sopenharmony_ci const VkBufferImageCopy2 *region) 91bf215546Sopenharmony_ci{ 92bf215546Sopenharmony_ci struct radv_meta_saved_state saved_state; 93bf215546Sopenharmony_ci bool cs; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci /* The Vulkan 1.0 spec says "dstImage must have a sample count equal to 96bf215546Sopenharmony_ci * VK_SAMPLE_COUNT_1_BIT." 97bf215546Sopenharmony_ci */ 98bf215546Sopenharmony_ci assert(image->info.samples == 1); 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci cs = cmd_buffer->qf == RADV_QUEUE_COMPUTE || 101bf215546Sopenharmony_ci !radv_image_is_renderable(cmd_buffer->device, image); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci /* VK_EXT_conditional_rendering says that copy commands should not be 104bf215546Sopenharmony_ci * affected by conditional rendering. 105bf215546Sopenharmony_ci */ 106bf215546Sopenharmony_ci radv_meta_save(&saved_state, cmd_buffer, 107bf215546Sopenharmony_ci (cs ? RADV_META_SAVE_COMPUTE_PIPELINE : RADV_META_SAVE_GRAPHICS_PIPELINE) | 108bf215546Sopenharmony_ci RADV_META_SAVE_CONSTANTS | RADV_META_SAVE_DESCRIPTORS | 109bf215546Sopenharmony_ci RADV_META_SUSPEND_PREDICATING); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci /** 112bf215546Sopenharmony_ci * From the Vulkan 1.0.6 spec: 18.3 Copying Data Between Images 113bf215546Sopenharmony_ci * extent is the size in texels of the source image to copy in width, 114bf215546Sopenharmony_ci * height and depth. 1D images use only x and width. 2D images use x, y, 115bf215546Sopenharmony_ci * width and height. 3D images use x, y, z, width, height and depth. 116bf215546Sopenharmony_ci * 117bf215546Sopenharmony_ci * 118bf215546Sopenharmony_ci * Also, convert the offsets and extent from units of texels to units of 119bf215546Sopenharmony_ci * blocks - which is the highest resolution accessible in this command. 120bf215546Sopenharmony_ci */ 121bf215546Sopenharmony_ci const VkOffset3D img_offset_el = vk_image_offset_to_elements(&image->vk, region->imageOffset); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci /* Start creating blit rect */ 124bf215546Sopenharmony_ci const VkExtent3D img_extent_el = vk_image_extent_to_elements(&image->vk, region->imageExtent); 125bf215546Sopenharmony_ci struct radv_meta_blit2d_rect rect = { 126bf215546Sopenharmony_ci .width = img_extent_el.width, 127bf215546Sopenharmony_ci .height = img_extent_el.height, 128bf215546Sopenharmony_ci }; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci /* Create blit surfaces */ 131bf215546Sopenharmony_ci struct radv_meta_blit2d_surf img_bsurf = blit_surf_for_image_level_layer( 132bf215546Sopenharmony_ci image, layout, ®ion->imageSubresource, region->imageSubresource.aspectMask); 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci if (!radv_is_buffer_format_supported(img_bsurf.format, NULL)) { 135bf215546Sopenharmony_ci uint32_t queue_mask = radv_image_queue_family_mask(image, cmd_buffer->qf, 136bf215546Sopenharmony_ci cmd_buffer->qf); 137bf215546Sopenharmony_ci bool compressed = 138bf215546Sopenharmony_ci radv_layout_dcc_compressed(cmd_buffer->device, image, region->imageSubresource.mipLevel, 139bf215546Sopenharmony_ci layout, false, queue_mask); 140bf215546Sopenharmony_ci if (compressed) { 141bf215546Sopenharmony_ci radv_decompress_dcc(cmd_buffer, image, 142bf215546Sopenharmony_ci &(VkImageSubresourceRange){ 143bf215546Sopenharmony_ci .aspectMask = region->imageSubresource.aspectMask, 144bf215546Sopenharmony_ci .baseMipLevel = region->imageSubresource.mipLevel, 145bf215546Sopenharmony_ci .levelCount = 1, 146bf215546Sopenharmony_ci .baseArrayLayer = region->imageSubresource.baseArrayLayer, 147bf215546Sopenharmony_ci .layerCount = region->imageSubresource.layerCount, 148bf215546Sopenharmony_ci }); 149bf215546Sopenharmony_ci img_bsurf.disable_compression = true; 150bf215546Sopenharmony_ci } 151bf215546Sopenharmony_ci img_bsurf.format = vk_format_for_size(vk_format_get_blocksize(img_bsurf.format)); 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci const struct vk_image_buffer_layout buf_layout = vk_image_buffer_copy_layout(&image->vk, region); 155bf215546Sopenharmony_ci struct radv_meta_blit2d_buffer buf_bsurf = { 156bf215546Sopenharmony_ci .bs = img_bsurf.bs, 157bf215546Sopenharmony_ci .format = img_bsurf.format, 158bf215546Sopenharmony_ci .buffer = buffer, 159bf215546Sopenharmony_ci .offset = region->bufferOffset, 160bf215546Sopenharmony_ci .pitch = buf_layout.row_stride_B / buf_layout.element_size_B, 161bf215546Sopenharmony_ci }; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci if (image->vk.image_type == VK_IMAGE_TYPE_3D) 164bf215546Sopenharmony_ci img_bsurf.layer = img_offset_el.z; 165bf215546Sopenharmony_ci /* Loop through each 3D or array slice */ 166bf215546Sopenharmony_ci unsigned num_slices_3d = img_extent_el.depth; 167bf215546Sopenharmony_ci unsigned num_slices_array = region->imageSubresource.layerCount; 168bf215546Sopenharmony_ci unsigned slice_3d = 0; 169bf215546Sopenharmony_ci unsigned slice_array = 0; 170bf215546Sopenharmony_ci while (slice_3d < num_slices_3d && slice_array < num_slices_array) { 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci rect.dst_x = img_offset_el.x; 173bf215546Sopenharmony_ci rect.dst_y = img_offset_el.y; 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci /* Perform Blit */ 176bf215546Sopenharmony_ci if (cs) { 177bf215546Sopenharmony_ci radv_meta_buffer_to_image_cs(cmd_buffer, &buf_bsurf, &img_bsurf, 1, &rect); 178bf215546Sopenharmony_ci } else { 179bf215546Sopenharmony_ci radv_meta_blit2d(cmd_buffer, NULL, &buf_bsurf, &img_bsurf, 1, &rect); 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci /* Once we've done the blit, all of the actual information about 183bf215546Sopenharmony_ci * the image is embedded in the command buffer so we can just 184bf215546Sopenharmony_ci * increment the offset directly in the image effectively 185bf215546Sopenharmony_ci * re-binding it to different backing memory. 186bf215546Sopenharmony_ci */ 187bf215546Sopenharmony_ci buf_bsurf.offset += buf_layout.image_stride_B; 188bf215546Sopenharmony_ci img_bsurf.layer++; 189bf215546Sopenharmony_ci if (image->vk.image_type == VK_IMAGE_TYPE_3D) 190bf215546Sopenharmony_ci slice_3d++; 191bf215546Sopenharmony_ci else 192bf215546Sopenharmony_ci slice_array++; 193bf215546Sopenharmony_ci } 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci radv_meta_restore(&saved_state, cmd_buffer); 196bf215546Sopenharmony_ci} 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL 199bf215546Sopenharmony_ciradv_CmdCopyBufferToImage2(VkCommandBuffer commandBuffer, 200bf215546Sopenharmony_ci const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo) 201bf215546Sopenharmony_ci{ 202bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer); 203bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_buffer, src_buffer, pCopyBufferToImageInfo->srcBuffer); 204bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_image, dst_image, pCopyBufferToImageInfo->dstImage); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci for (unsigned r = 0; r < pCopyBufferToImageInfo->regionCount; r++) { 207bf215546Sopenharmony_ci copy_buffer_to_image(cmd_buffer, src_buffer, dst_image, 208bf215546Sopenharmony_ci pCopyBufferToImageInfo->dstImageLayout, 209bf215546Sopenharmony_ci &pCopyBufferToImageInfo->pRegions[r]); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (cmd_buffer->device->physical_device->emulate_etc2 && 213bf215546Sopenharmony_ci vk_format_description(dst_image->vk.format)->layout == UTIL_FORMAT_LAYOUT_ETC) { 214bf215546Sopenharmony_ci cmd_buffer->state.flush_bits |= 215bf215546Sopenharmony_ci RADV_CMD_FLAG_CS_PARTIAL_FLUSH | RADV_CMD_FLAG_PS_PARTIAL_FLUSH | 216bf215546Sopenharmony_ci radv_src_access_flush(cmd_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, dst_image) | 217bf215546Sopenharmony_ci radv_dst_access_flush( 218bf215546Sopenharmony_ci cmd_buffer, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, dst_image); 219bf215546Sopenharmony_ci for (unsigned r = 0; r < pCopyBufferToImageInfo->regionCount; r++) { 220bf215546Sopenharmony_ci radv_meta_decode_etc(cmd_buffer, dst_image, pCopyBufferToImageInfo->dstImageLayout, 221bf215546Sopenharmony_ci &pCopyBufferToImageInfo->pRegions[r].imageSubresource, 222bf215546Sopenharmony_ci pCopyBufferToImageInfo->pRegions[r].imageOffset, 223bf215546Sopenharmony_ci pCopyBufferToImageInfo->pRegions[r].imageExtent); 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci} 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_cistatic void 229bf215546Sopenharmony_cicopy_image_to_buffer(struct radv_cmd_buffer *cmd_buffer, struct radv_buffer *buffer, 230bf215546Sopenharmony_ci struct radv_image *image, VkImageLayout layout, 231bf215546Sopenharmony_ci const VkBufferImageCopy2 *region) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci if (cmd_buffer->qf == RADV_QUEUE_TRANSFER) { 234bf215546Sopenharmony_ci /* RADV_QUEUE_TRANSFER should only be used for the prime blit */ 235bf215546Sopenharmony_ci assert(!region->imageOffset.x && !region->imageOffset.y && !region->imageOffset.z); 236bf215546Sopenharmony_ci assert(image->vk.image_type == VK_IMAGE_TYPE_2D); 237bf215546Sopenharmony_ci assert(image->info.width == region->imageExtent.width); 238bf215546Sopenharmony_ci assert(image->info.height == region->imageExtent.height); 239bf215546Sopenharmony_ci ASSERTED bool res = radv_sdma_copy_image(cmd_buffer, image, buffer, region); 240bf215546Sopenharmony_ci assert(res); 241bf215546Sopenharmony_ci radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, image->bindings[0].bo); 242bf215546Sopenharmony_ci radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, buffer->bo); 243bf215546Sopenharmony_ci return; 244bf215546Sopenharmony_ci } 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci struct radv_meta_saved_state saved_state; 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci /* VK_EXT_conditional_rendering says that copy commands should not be 249bf215546Sopenharmony_ci * affected by conditional rendering. 250bf215546Sopenharmony_ci */ 251bf215546Sopenharmony_ci radv_meta_save(&saved_state, cmd_buffer, 252bf215546Sopenharmony_ci RADV_META_SAVE_COMPUTE_PIPELINE | RADV_META_SAVE_CONSTANTS | 253bf215546Sopenharmony_ci RADV_META_SAVE_DESCRIPTORS | RADV_META_SUSPEND_PREDICATING); 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci /** 256bf215546Sopenharmony_ci * From the Vulkan 1.0.6 spec: 18.3 Copying Data Between Images 257bf215546Sopenharmony_ci * extent is the size in texels of the source image to copy in width, 258bf215546Sopenharmony_ci * height and depth. 1D images use only x and width. 2D images use x, y, 259bf215546Sopenharmony_ci * width and height. 3D images use x, y, z, width, height and depth. 260bf215546Sopenharmony_ci * 261bf215546Sopenharmony_ci * 262bf215546Sopenharmony_ci * Also, convert the offsets and extent from units of texels to units of 263bf215546Sopenharmony_ci * blocks - which is the highest resolution accessible in this command. 264bf215546Sopenharmony_ci */ 265bf215546Sopenharmony_ci const VkOffset3D img_offset_el = vk_image_offset_to_elements(&image->vk, region->imageOffset); 266bf215546Sopenharmony_ci const VkExtent3D bufferExtent = { 267bf215546Sopenharmony_ci .width = region->bufferRowLength ? region->bufferRowLength : region->imageExtent.width, 268bf215546Sopenharmony_ci .height = region->bufferImageHeight ? region->bufferImageHeight : region->imageExtent.height, 269bf215546Sopenharmony_ci }; 270bf215546Sopenharmony_ci const VkExtent3D buf_extent_el = vk_image_extent_to_elements(&image->vk, bufferExtent); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci /* Start creating blit rect */ 273bf215546Sopenharmony_ci const VkExtent3D img_extent_el = vk_image_extent_to_elements(&image->vk, region->imageExtent); 274bf215546Sopenharmony_ci struct radv_meta_blit2d_rect rect = { 275bf215546Sopenharmony_ci .width = img_extent_el.width, 276bf215546Sopenharmony_ci .height = img_extent_el.height, 277bf215546Sopenharmony_ci }; 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci /* Create blit surfaces */ 280bf215546Sopenharmony_ci struct radv_meta_blit2d_surf img_info = blit_surf_for_image_level_layer( 281bf215546Sopenharmony_ci image, layout, ®ion->imageSubresource, region->imageSubresource.aspectMask); 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci if (!radv_is_buffer_format_supported(img_info.format, NULL)) { 284bf215546Sopenharmony_ci uint32_t queue_mask = radv_image_queue_family_mask(image, cmd_buffer->qf, 285bf215546Sopenharmony_ci cmd_buffer->qf); 286bf215546Sopenharmony_ci bool compressed = 287bf215546Sopenharmony_ci radv_layout_dcc_compressed(cmd_buffer->device, image, region->imageSubresource.mipLevel, 288bf215546Sopenharmony_ci layout, false, queue_mask); 289bf215546Sopenharmony_ci if (compressed) { 290bf215546Sopenharmony_ci radv_decompress_dcc(cmd_buffer, image, 291bf215546Sopenharmony_ci &(VkImageSubresourceRange){ 292bf215546Sopenharmony_ci .aspectMask = region->imageSubresource.aspectMask, 293bf215546Sopenharmony_ci .baseMipLevel = region->imageSubresource.mipLevel, 294bf215546Sopenharmony_ci .levelCount = 1, 295bf215546Sopenharmony_ci .baseArrayLayer = region->imageSubresource.baseArrayLayer, 296bf215546Sopenharmony_ci .layerCount = region->imageSubresource.layerCount, 297bf215546Sopenharmony_ci }); 298bf215546Sopenharmony_ci img_info.disable_compression = true; 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci img_info.format = vk_format_for_size(vk_format_get_blocksize(img_info.format)); 301bf215546Sopenharmony_ci } 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci struct radv_meta_blit2d_buffer buf_info = { 304bf215546Sopenharmony_ci .bs = img_info.bs, 305bf215546Sopenharmony_ci .format = img_info.format, 306bf215546Sopenharmony_ci .buffer = buffer, 307bf215546Sopenharmony_ci .offset = region->bufferOffset, 308bf215546Sopenharmony_ci .pitch = buf_extent_el.width, 309bf215546Sopenharmony_ci }; 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci if (image->vk.image_type == VK_IMAGE_TYPE_3D) 312bf215546Sopenharmony_ci img_info.layer = img_offset_el.z; 313bf215546Sopenharmony_ci /* Loop through each 3D or array slice */ 314bf215546Sopenharmony_ci unsigned num_slices_3d = img_extent_el.depth; 315bf215546Sopenharmony_ci unsigned num_slices_array = region->imageSubresource.layerCount; 316bf215546Sopenharmony_ci unsigned slice_3d = 0; 317bf215546Sopenharmony_ci unsigned slice_array = 0; 318bf215546Sopenharmony_ci while (slice_3d < num_slices_3d && slice_array < num_slices_array) { 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci rect.src_x = img_offset_el.x; 321bf215546Sopenharmony_ci rect.src_y = img_offset_el.y; 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci /* Perform Blit */ 324bf215546Sopenharmony_ci radv_meta_image_to_buffer(cmd_buffer, &img_info, &buf_info, 1, &rect); 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci buf_info.offset += buf_extent_el.width * buf_extent_el.height * buf_info.bs; 327bf215546Sopenharmony_ci img_info.layer++; 328bf215546Sopenharmony_ci if (image->vk.image_type == VK_IMAGE_TYPE_3D) 329bf215546Sopenharmony_ci slice_3d++; 330bf215546Sopenharmony_ci else 331bf215546Sopenharmony_ci slice_array++; 332bf215546Sopenharmony_ci } 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci radv_meta_restore(&saved_state, cmd_buffer); 335bf215546Sopenharmony_ci} 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL 338bf215546Sopenharmony_ciradv_CmdCopyImageToBuffer2(VkCommandBuffer commandBuffer, 339bf215546Sopenharmony_ci const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo) 340bf215546Sopenharmony_ci{ 341bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer); 342bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_image, src_image, pCopyImageToBufferInfo->srcImage); 343bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_buffer, dst_buffer, pCopyImageToBufferInfo->dstBuffer); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci for (unsigned r = 0; r < pCopyImageToBufferInfo->regionCount; r++) { 346bf215546Sopenharmony_ci copy_image_to_buffer(cmd_buffer, dst_buffer, src_image, 347bf215546Sopenharmony_ci pCopyImageToBufferInfo->srcImageLayout, 348bf215546Sopenharmony_ci &pCopyImageToBufferInfo->pRegions[r]); 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci} 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_cistatic void 353bf215546Sopenharmony_cicopy_image(struct radv_cmd_buffer *cmd_buffer, struct radv_image *src_image, 354bf215546Sopenharmony_ci VkImageLayout src_image_layout, struct radv_image *dst_image, 355bf215546Sopenharmony_ci VkImageLayout dst_image_layout, const VkImageCopy2 *region) 356bf215546Sopenharmony_ci{ 357bf215546Sopenharmony_ci struct radv_meta_saved_state saved_state; 358bf215546Sopenharmony_ci bool cs; 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci /* From the Vulkan 1.0 spec: 361bf215546Sopenharmony_ci * 362bf215546Sopenharmony_ci * vkCmdCopyImage can be used to copy image data between multisample 363bf215546Sopenharmony_ci * images, but both images must have the same number of samples. 364bf215546Sopenharmony_ci */ 365bf215546Sopenharmony_ci assert(src_image->info.samples == dst_image->info.samples); 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci cs = cmd_buffer->qf == RADV_QUEUE_COMPUTE || 368bf215546Sopenharmony_ci !radv_image_is_renderable(cmd_buffer->device, dst_image); 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci /* VK_EXT_conditional_rendering says that copy commands should not be 371bf215546Sopenharmony_ci * affected by conditional rendering. 372bf215546Sopenharmony_ci */ 373bf215546Sopenharmony_ci radv_meta_save(&saved_state, cmd_buffer, 374bf215546Sopenharmony_ci (cs ? RADV_META_SAVE_COMPUTE_PIPELINE : RADV_META_SAVE_GRAPHICS_PIPELINE) | 375bf215546Sopenharmony_ci RADV_META_SAVE_CONSTANTS | RADV_META_SAVE_DESCRIPTORS | 376bf215546Sopenharmony_ci RADV_META_SUSPEND_PREDICATING); 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci if (cs) { 379bf215546Sopenharmony_ci /* For partial copies, HTILE should be decompressed before copying because the metadata is 380bf215546Sopenharmony_ci * re-initialized to the uncompressed state after. 381bf215546Sopenharmony_ci */ 382bf215546Sopenharmony_ci uint32_t queue_mask = radv_image_queue_family_mask(dst_image, cmd_buffer->qf, 383bf215546Sopenharmony_ci cmd_buffer->qf); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci if (radv_layout_is_htile_compressed(cmd_buffer->device, dst_image, dst_image_layout, 386bf215546Sopenharmony_ci false, queue_mask) && 387bf215546Sopenharmony_ci (region->dstOffset.x || region->dstOffset.y || region->dstOffset.z || 388bf215546Sopenharmony_ci region->extent.width != dst_image->info.width || 389bf215546Sopenharmony_ci region->extent.height != dst_image->info.height || 390bf215546Sopenharmony_ci region->extent.depth != dst_image->info.depth)) { 391bf215546Sopenharmony_ci u_foreach_bit(i, region->dstSubresource.aspectMask) { 392bf215546Sopenharmony_ci unsigned aspect_mask = 1u << i; 393bf215546Sopenharmony_ci radv_expand_depth_stencil(cmd_buffer, dst_image, 394bf215546Sopenharmony_ci &(VkImageSubresourceRange){ 395bf215546Sopenharmony_ci .aspectMask = aspect_mask, 396bf215546Sopenharmony_ci .baseMipLevel = region->dstSubresource.mipLevel, 397bf215546Sopenharmony_ci .levelCount = 1, 398bf215546Sopenharmony_ci .baseArrayLayer = region->dstSubresource.baseArrayLayer, 399bf215546Sopenharmony_ci .layerCount = region->dstSubresource.layerCount, 400bf215546Sopenharmony_ci }, NULL); 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci } 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci VkImageAspectFlags src_aspects[3] = { region->srcSubresource.aspectMask }; 406bf215546Sopenharmony_ci VkImageAspectFlags dst_aspects[3] = { region->dstSubresource.aspectMask }; 407bf215546Sopenharmony_ci unsigned aspect_count = 1; 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci if (region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT && 410bf215546Sopenharmony_ci src_image->plane_count > 1) { 411bf215546Sopenharmony_ci static const VkImageAspectFlags all_planes[3] = { 412bf215546Sopenharmony_ci VK_IMAGE_ASPECT_PLANE_0_BIT, 413bf215546Sopenharmony_ci VK_IMAGE_ASPECT_PLANE_1_BIT, 414bf215546Sopenharmony_ci VK_IMAGE_ASPECT_PLANE_2_BIT 415bf215546Sopenharmony_ci }; 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci aspect_count = src_image->plane_count; 418bf215546Sopenharmony_ci for (unsigned i = 0; i < aspect_count; i++) { 419bf215546Sopenharmony_ci src_aspects[i] = all_planes[i]; 420bf215546Sopenharmony_ci dst_aspects[i] = all_planes[i]; 421bf215546Sopenharmony_ci } 422bf215546Sopenharmony_ci } 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci for (unsigned a = 0; a < aspect_count; ++a) { 425bf215546Sopenharmony_ci /* Create blit surfaces */ 426bf215546Sopenharmony_ci struct radv_meta_blit2d_surf b_src = blit_surf_for_image_level_layer( 427bf215546Sopenharmony_ci src_image, src_image_layout, ®ion->srcSubresource, src_aspects[a]); 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci struct radv_meta_blit2d_surf b_dst = blit_surf_for_image_level_layer( 430bf215546Sopenharmony_ci dst_image, dst_image_layout, ®ion->dstSubresource, dst_aspects[a]); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci uint32_t dst_queue_mask = radv_image_queue_family_mask( 433bf215546Sopenharmony_ci dst_image, cmd_buffer->qf, cmd_buffer->qf); 434bf215546Sopenharmony_ci bool dst_compressed = radv_layout_dcc_compressed(cmd_buffer->device, dst_image, 435bf215546Sopenharmony_ci region->dstSubresource.mipLevel, 436bf215546Sopenharmony_ci dst_image_layout, false, dst_queue_mask); 437bf215546Sopenharmony_ci uint32_t src_queue_mask = radv_image_queue_family_mask( 438bf215546Sopenharmony_ci src_image, cmd_buffer->qf, cmd_buffer->qf); 439bf215546Sopenharmony_ci bool src_compressed = radv_layout_dcc_compressed(cmd_buffer->device, src_image, 440bf215546Sopenharmony_ci region->srcSubresource.mipLevel, 441bf215546Sopenharmony_ci src_image_layout, false, src_queue_mask); 442bf215546Sopenharmony_ci bool need_dcc_sign_reinterpret = false; 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci if (!src_compressed || 445bf215546Sopenharmony_ci (radv_dcc_formats_compatible(cmd_buffer->device->physical_device->rad_info.gfx_level, 446bf215546Sopenharmony_ci b_src.format, b_dst.format, &need_dcc_sign_reinterpret) && 447bf215546Sopenharmony_ci !need_dcc_sign_reinterpret)) { 448bf215546Sopenharmony_ci b_src.format = b_dst.format; 449bf215546Sopenharmony_ci } else if (!dst_compressed) { 450bf215546Sopenharmony_ci b_dst.format = b_src.format; 451bf215546Sopenharmony_ci } else { 452bf215546Sopenharmony_ci radv_decompress_dcc(cmd_buffer, dst_image, 453bf215546Sopenharmony_ci &(VkImageSubresourceRange){ 454bf215546Sopenharmony_ci .aspectMask = dst_aspects[a], 455bf215546Sopenharmony_ci .baseMipLevel = region->dstSubresource.mipLevel, 456bf215546Sopenharmony_ci .levelCount = 1, 457bf215546Sopenharmony_ci .baseArrayLayer = region->dstSubresource.baseArrayLayer, 458bf215546Sopenharmony_ci .layerCount = region->dstSubresource.layerCount, 459bf215546Sopenharmony_ci }); 460bf215546Sopenharmony_ci b_dst.format = b_src.format; 461bf215546Sopenharmony_ci b_dst.disable_compression = true; 462bf215546Sopenharmony_ci } 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci /** 465bf215546Sopenharmony_ci * From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images 466bf215546Sopenharmony_ci * imageExtent is the size in texels of the image to copy in width, height 467bf215546Sopenharmony_ci * and depth. 1D images use only x and width. 2D images use x, y, width 468bf215546Sopenharmony_ci * and height. 3D images use x, y, z, width, height and depth. 469bf215546Sopenharmony_ci * 470bf215546Sopenharmony_ci * Also, convert the offsets and extent from units of texels to units of 471bf215546Sopenharmony_ci * blocks - which is the highest resolution accessible in this command. 472bf215546Sopenharmony_ci */ 473bf215546Sopenharmony_ci const VkOffset3D dst_offset_el = 474bf215546Sopenharmony_ci vk_image_offset_to_elements(&dst_image->vk, region->dstOffset); 475bf215546Sopenharmony_ci const VkOffset3D src_offset_el = 476bf215546Sopenharmony_ci vk_image_offset_to_elements(&src_image->vk, region->srcOffset); 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci /* 479bf215546Sopenharmony_ci * From Vulkan 1.0.68, "Copying Data Between Images": 480bf215546Sopenharmony_ci * "When copying between compressed and uncompressed formats 481bf215546Sopenharmony_ci * the extent members represent the texel dimensions of the 482bf215546Sopenharmony_ci * source image and not the destination." 483bf215546Sopenharmony_ci * However, we must use the destination image type to avoid 484bf215546Sopenharmony_ci * clamping depth when copying multiple layers of a 2D image to 485bf215546Sopenharmony_ci * a 3D image. 486bf215546Sopenharmony_ci */ 487bf215546Sopenharmony_ci const VkExtent3D img_extent_el = vk_image_extent_to_elements(&src_image->vk, region->extent); 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci /* Start creating blit rect */ 490bf215546Sopenharmony_ci struct radv_meta_blit2d_rect rect = { 491bf215546Sopenharmony_ci .width = img_extent_el.width, 492bf215546Sopenharmony_ci .height = img_extent_el.height, 493bf215546Sopenharmony_ci }; 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci if (src_image->vk.image_type == VK_IMAGE_TYPE_3D) 496bf215546Sopenharmony_ci b_src.layer = src_offset_el.z; 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci if (dst_image->vk.image_type == VK_IMAGE_TYPE_3D) 499bf215546Sopenharmony_ci b_dst.layer = dst_offset_el.z; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci /* Loop through each 3D or array slice */ 502bf215546Sopenharmony_ci unsigned num_slices_3d = img_extent_el.depth; 503bf215546Sopenharmony_ci unsigned num_slices_array = region->dstSubresource.layerCount; 504bf215546Sopenharmony_ci unsigned slice_3d = 0; 505bf215546Sopenharmony_ci unsigned slice_array = 0; 506bf215546Sopenharmony_ci while (slice_3d < num_slices_3d && slice_array < num_slices_array) { 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci /* Finish creating blit rect */ 509bf215546Sopenharmony_ci rect.dst_x = dst_offset_el.x; 510bf215546Sopenharmony_ci rect.dst_y = dst_offset_el.y; 511bf215546Sopenharmony_ci rect.src_x = src_offset_el.x; 512bf215546Sopenharmony_ci rect.src_y = src_offset_el.y; 513bf215546Sopenharmony_ci 514bf215546Sopenharmony_ci /* Perform Blit */ 515bf215546Sopenharmony_ci if (cs) { 516bf215546Sopenharmony_ci radv_meta_image_to_image_cs(cmd_buffer, &b_src, &b_dst, 1, &rect); 517bf215546Sopenharmony_ci } else { 518bf215546Sopenharmony_ci if (radv_can_use_fmask_copy(cmd_buffer, b_src.image, b_dst.image, 1, &rect)) { 519bf215546Sopenharmony_ci radv_fmask_copy(cmd_buffer, &b_src, &b_dst); 520bf215546Sopenharmony_ci } else { 521bf215546Sopenharmony_ci radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect); 522bf215546Sopenharmony_ci } 523bf215546Sopenharmony_ci } 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci b_src.layer++; 526bf215546Sopenharmony_ci b_dst.layer++; 527bf215546Sopenharmony_ci if (dst_image->vk.image_type == VK_IMAGE_TYPE_3D) 528bf215546Sopenharmony_ci slice_3d++; 529bf215546Sopenharmony_ci else 530bf215546Sopenharmony_ci slice_array++; 531bf215546Sopenharmony_ci } 532bf215546Sopenharmony_ci } 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci if (cs) { 535bf215546Sopenharmony_ci /* Fixup HTILE after a copy on compute. */ 536bf215546Sopenharmony_ci uint32_t queue_mask = radv_image_queue_family_mask(dst_image, cmd_buffer->qf, 537bf215546Sopenharmony_ci cmd_buffer->qf); 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci if (radv_layout_is_htile_compressed(cmd_buffer->device, dst_image, dst_image_layout, 540bf215546Sopenharmony_ci false, queue_mask)) { 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH | RADV_CMD_FLAG_INV_VCACHE; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci VkImageSubresourceRange range = { 545bf215546Sopenharmony_ci .aspectMask = region->dstSubresource.aspectMask, 546bf215546Sopenharmony_ci .baseMipLevel = region->dstSubresource.mipLevel, 547bf215546Sopenharmony_ci .levelCount = 1, 548bf215546Sopenharmony_ci .baseArrayLayer = region->dstSubresource.baseArrayLayer, 549bf215546Sopenharmony_ci .layerCount = region->dstSubresource.layerCount, 550bf215546Sopenharmony_ci }; 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci uint32_t htile_value = radv_get_htile_initial_value(cmd_buffer->device, dst_image); 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci cmd_buffer->state.flush_bits |= radv_clear_htile(cmd_buffer, dst_image, &range, htile_value); 555bf215546Sopenharmony_ci } 556bf215546Sopenharmony_ci } 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci radv_meta_restore(&saved_state, cmd_buffer); 559bf215546Sopenharmony_ci} 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL 562bf215546Sopenharmony_ciradv_CmdCopyImage2(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo) 563bf215546Sopenharmony_ci{ 564bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer); 565bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_image, src_image, pCopyImageInfo->srcImage); 566bf215546Sopenharmony_ci RADV_FROM_HANDLE(radv_image, dst_image, pCopyImageInfo->dstImage); 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci for (unsigned r = 0; r < pCopyImageInfo->regionCount; r++) { 569bf215546Sopenharmony_ci copy_image(cmd_buffer, src_image, pCopyImageInfo->srcImageLayout, dst_image, 570bf215546Sopenharmony_ci pCopyImageInfo->dstImageLayout, &pCopyImageInfo->pRegions[r]); 571bf215546Sopenharmony_ci } 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci if (cmd_buffer->device->physical_device->emulate_etc2 && 574bf215546Sopenharmony_ci vk_format_description(dst_image->vk.format)->layout == UTIL_FORMAT_LAYOUT_ETC) { 575bf215546Sopenharmony_ci cmd_buffer->state.flush_bits |= 576bf215546Sopenharmony_ci RADV_CMD_FLAG_CS_PARTIAL_FLUSH | RADV_CMD_FLAG_PS_PARTIAL_FLUSH | 577bf215546Sopenharmony_ci radv_src_access_flush(cmd_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, dst_image) | 578bf215546Sopenharmony_ci radv_dst_access_flush( 579bf215546Sopenharmony_ci cmd_buffer, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, dst_image); 580bf215546Sopenharmony_ci for (unsigned r = 0; r < pCopyImageInfo->regionCount; r++) { 581bf215546Sopenharmony_ci radv_meta_decode_etc(cmd_buffer, dst_image, pCopyImageInfo->dstImageLayout, 582bf215546Sopenharmony_ci &pCopyImageInfo->pRegions[r].dstSubresource, 583bf215546Sopenharmony_ci pCopyImageInfo->pRegions[r].dstOffset, 584bf215546Sopenharmony_ci pCopyImageInfo->pRegions[r].extent); 585bf215546Sopenharmony_ci } 586bf215546Sopenharmony_ci } 587bf215546Sopenharmony_ci} 588