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 
27 static VkFormat
vk_format_for_size(int bs)28 vk_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 
48 static struct radv_meta_blit2d_surf
blit_surf_for_image_level_layer(struct radv_image *image, VkImageLayout layout, const VkImageSubresourceLayers *subres, VkImageAspectFlags aspect_mask)49 blit_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 
71 bool
radv_image_is_renderable(struct radv_device *device, struct radv_image *image)72 radv_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 
87 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)88 copy_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 
198 VKAPI_ATTR void VKAPI_CALL
radv_CmdCopyBufferToImage2(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo)199 radv_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 
228 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)229 copy_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 
337 VKAPI_ATTR void VKAPI_CALL
radv_CmdCopyImageToBuffer2(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo)338 radv_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 
352 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)353 copy_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 
561 VKAPI_ATTR void VKAPI_CALL
radv_CmdCopyImage2(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo)562 radv_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