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