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