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