radv: create pipeline layout objects for all meta operations
[mesa.git] / src / amd / vulkan / radv_meta_resolve.c
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 <assert.h>
25 #include <stdbool.h>
26
27 #include "radv_meta.h"
28 #include "radv_private.h"
29 #include "nir/nir_builder.h"
30 #include "sid.h"
31
32 /* emit 0, 0, 0, 1 */
33 static nir_shader *
34 build_nir_fs(void)
35 {
36 const struct glsl_type *vec4 = glsl_vec4_type();
37 nir_builder b;
38 nir_variable *f_color; /* vec4, fragment output color */
39
40 nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
41 b.shader->info.name = ralloc_asprintf(b.shader,
42 "meta_resolve_fs");
43
44 f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4,
45 "f_color");
46 f_color->data.location = FRAG_RESULT_DATA0;
47 nir_store_var(&b, f_color, nir_imm_vec4(&b, 0.0, 0.0, 0.0, 1.0), 0xf);
48
49 return b.shader;
50 }
51
52 static VkResult
53 create_pass(struct radv_device *device)
54 {
55 VkResult result;
56 VkDevice device_h = radv_device_to_handle(device);
57 const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
58 VkAttachmentDescription attachments[2];
59 int i;
60
61 for (i = 0; i < 2; i++) {
62 attachments[i].format = VK_FORMAT_UNDEFINED;
63 attachments[i].samples = 1;
64 attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
65 attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
66 }
67 attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
68 attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
69 attachments[1].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
70 attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
71
72 result = radv_CreateRenderPass(device_h,
73 &(VkRenderPassCreateInfo) {
74 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
75 .attachmentCount = 2,
76 .pAttachments = attachments,
77 .subpassCount = 1,
78 .pSubpasses = &(VkSubpassDescription) {
79 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
80 .inputAttachmentCount = 0,
81 .colorAttachmentCount = 2,
82 .pColorAttachments = (VkAttachmentReference[]) {
83 {
84 .attachment = 0,
85 .layout = VK_IMAGE_LAYOUT_GENERAL,
86 },
87 {
88 .attachment = 1,
89 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
90 },
91 },
92 .pResolveAttachments = NULL,
93 .pDepthStencilAttachment = &(VkAttachmentReference) {
94 .attachment = VK_ATTACHMENT_UNUSED,
95 },
96 .preserveAttachmentCount = 0,
97 .pPreserveAttachments = NULL,
98 },
99 .dependencyCount = 0,
100 },
101 alloc,
102 &device->meta_state.resolve.pass);
103
104 return result;
105 }
106
107 static VkResult
108 create_pipeline(struct radv_device *device,
109 VkShaderModule vs_module_h)
110 {
111 VkResult result;
112 VkDevice device_h = radv_device_to_handle(device);
113
114 struct radv_shader_module fs_module = {
115 .nir = build_nir_fs(),
116 };
117
118 if (!fs_module.nir) {
119 /* XXX: Need more accurate error */
120 result = VK_ERROR_OUT_OF_HOST_MEMORY;
121 goto cleanup;
122 }
123
124 VkPipelineLayoutCreateInfo pl_create_info = {
125 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
126 .setLayoutCount = 0,
127 .pSetLayouts = NULL,
128 .pushConstantRangeCount = 0,
129 .pPushConstantRanges = NULL,
130 };
131
132 result = radv_CreatePipelineLayout(radv_device_to_handle(device),
133 &pl_create_info,
134 &device->meta_state.alloc,
135 &device->meta_state.resolve.p_layout);
136 if (result != VK_SUCCESS)
137 goto cleanup;
138
139 result = radv_graphics_pipeline_create(device_h,
140 radv_pipeline_cache_to_handle(&device->meta_state.cache),
141 &(VkGraphicsPipelineCreateInfo) {
142 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
143 .stageCount = 2,
144 .pStages = (VkPipelineShaderStageCreateInfo[]) {
145 {
146 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
147 .stage = VK_SHADER_STAGE_VERTEX_BIT,
148 .module = vs_module_h,
149 .pName = "main",
150 },
151 {
152 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
153 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
154 .module = radv_shader_module_to_handle(&fs_module),
155 .pName = "main",
156 },
157 },
158 .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
159 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
160 .vertexBindingDescriptionCount = 0,
161 .vertexAttributeDescriptionCount = 0,
162 },
163 .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
164 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
165 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
166 .primitiveRestartEnable = false,
167 },
168 .pViewportState = &(VkPipelineViewportStateCreateInfo) {
169 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
170 .viewportCount = 1,
171 .scissorCount = 1,
172 },
173 .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
174 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
175 .depthClampEnable = false,
176 .rasterizerDiscardEnable = false,
177 .polygonMode = VK_POLYGON_MODE_FILL,
178 .cullMode = VK_CULL_MODE_NONE,
179 .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
180 },
181 .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
182 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
183 .rasterizationSamples = 1,
184 .sampleShadingEnable = false,
185 .pSampleMask = NULL,
186 .alphaToCoverageEnable = false,
187 .alphaToOneEnable = false,
188 },
189 .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
190 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
191 .logicOpEnable = false,
192 .attachmentCount = 2,
193 .pAttachments = (VkPipelineColorBlendAttachmentState []) {
194 {
195 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
196 VK_COLOR_COMPONENT_G_BIT |
197 VK_COLOR_COMPONENT_B_BIT |
198 VK_COLOR_COMPONENT_A_BIT,
199 },
200 {
201 .colorWriteMask = 0,
202
203 }
204 },
205 },
206 .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
207 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
208 .dynamicStateCount = 2,
209 .pDynamicStates = (VkDynamicState[]) {
210 VK_DYNAMIC_STATE_VIEWPORT,
211 VK_DYNAMIC_STATE_SCISSOR,
212 },
213 },
214 .layout = device->meta_state.resolve.p_layout,
215 .renderPass = device->meta_state.resolve.pass,
216 .subpass = 0,
217 },
218 &(struct radv_graphics_pipeline_create_info) {
219 .use_rectlist = true,
220 .custom_blend_mode = V_028808_CB_RESOLVE,
221 },
222 &device->meta_state.alloc,
223 &device->meta_state.resolve.pipeline);
224 if (result != VK_SUCCESS)
225 goto cleanup;
226
227 goto cleanup;
228
229 cleanup:
230 ralloc_free(fs_module.nir);
231 return result;
232 }
233
234 void
235 radv_device_finish_meta_resolve_state(struct radv_device *device)
236 {
237 struct radv_meta_state *state = &device->meta_state;
238
239 radv_DestroyRenderPass(radv_device_to_handle(device),
240 state->resolve.pass, &state->alloc);
241 radv_DestroyPipelineLayout(radv_device_to_handle(device),
242 state->resolve.p_layout, &state->alloc);
243 radv_DestroyPipeline(radv_device_to_handle(device),
244 state->resolve.pipeline, &state->alloc);
245 }
246
247 VkResult
248 radv_device_init_meta_resolve_state(struct radv_device *device)
249 {
250 VkResult res = VK_SUCCESS;
251
252 struct radv_shader_module vs_module = { .nir = radv_meta_build_nir_vs_generate_vertices() };
253 if (!vs_module.nir) {
254 /* XXX: Need more accurate error */
255 res = VK_ERROR_OUT_OF_HOST_MEMORY;
256 goto fail;
257 }
258
259 res = create_pass(device);
260 if (res != VK_SUCCESS)
261 goto fail;
262
263 VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
264 res = create_pipeline(device, vs_module_h);
265 if (res != VK_SUCCESS)
266 goto fail;
267
268 goto cleanup;
269
270 fail:
271 radv_device_finish_meta_resolve_state(device);
272
273 cleanup:
274 ralloc_free(vs_module.nir);
275
276 return res;
277 }
278
279 static void
280 emit_resolve(struct radv_cmd_buffer *cmd_buffer,
281 const VkOffset2D *dest_offset,
282 const VkExtent2D *resolve_extent)
283 {
284 struct radv_device *device = cmd_buffer->device;
285 VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
286
287 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
288
289 radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
290 device->meta_state.resolve.pipeline);
291
292 radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
293 .x = dest_offset->x,
294 .y = dest_offset->y,
295 .width = resolve_extent->width,
296 .height = resolve_extent->height,
297 .minDepth = 0.0f,
298 .maxDepth = 1.0f
299 });
300
301 radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkRect2D) {
302 .offset = *dest_offset,
303 .extent = *resolve_extent,
304 });
305
306 radv_CmdDraw(cmd_buffer_h, 3, 1, 0, 0);
307 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
308 }
309
310 enum radv_resolve_method {
311 RESOLVE_HW,
312 RESOLVE_COMPUTE,
313 RESOLVE_FRAGMENT,
314 };
315
316 static void radv_pick_resolve_method_images(struct radv_image *src_image,
317 struct radv_image *dest_image,
318 enum radv_resolve_method *method)
319
320 {
321 if (dest_image->surface.micro_tile_mode != src_image->surface.micro_tile_mode) {
322 if (dest_image->surface.num_dcc_levels > 0)
323 *method = RESOLVE_FRAGMENT;
324 else
325 *method = RESOLVE_COMPUTE;
326 }
327 }
328
329 void radv_CmdResolveImage(
330 VkCommandBuffer cmd_buffer_h,
331 VkImage src_image_h,
332 VkImageLayout src_image_layout,
333 VkImage dest_image_h,
334 VkImageLayout dest_image_layout,
335 uint32_t region_count,
336 const VkImageResolve* regions)
337 {
338 RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, cmd_buffer_h);
339 RADV_FROM_HANDLE(radv_image, src_image, src_image_h);
340 RADV_FROM_HANDLE(radv_image, dest_image, dest_image_h);
341 struct radv_device *device = cmd_buffer->device;
342 struct radv_meta_saved_state saved_state;
343 VkDevice device_h = radv_device_to_handle(device);
344 enum radv_resolve_method resolve_method = RESOLVE_HW;
345 /* we can use the hw resolve only for single full resolves */
346 if (region_count == 1) {
347 if (regions[0].srcOffset.x ||
348 regions[0].srcOffset.y ||
349 regions[0].srcOffset.z)
350 resolve_method = RESOLVE_COMPUTE;
351 if (regions[0].dstOffset.x ||
352 regions[0].dstOffset.y ||
353 regions[0].dstOffset.z)
354 resolve_method = RESOLVE_COMPUTE;
355
356 if (regions[0].extent.width != src_image->info.width ||
357 regions[0].extent.height != src_image->info.height ||
358 regions[0].extent.depth != src_image->info.depth)
359 resolve_method = RESOLVE_COMPUTE;
360 } else
361 resolve_method = RESOLVE_COMPUTE;
362
363 radv_pick_resolve_method_images(src_image, dest_image,
364 &resolve_method);
365
366 if (resolve_method == RESOLVE_FRAGMENT) {
367 radv_meta_resolve_fragment_image(cmd_buffer,
368 src_image,
369 src_image_layout,
370 dest_image,
371 dest_image_layout,
372 region_count, regions);
373 return;
374 }
375
376 if (resolve_method == RESOLVE_COMPUTE) {
377 radv_meta_resolve_compute_image(cmd_buffer,
378 src_image,
379 src_image_layout,
380 dest_image,
381 dest_image_layout,
382 region_count, regions);
383 return;
384 }
385
386 radv_meta_save(&saved_state, cmd_buffer,
387 RADV_META_SAVE_GRAPHICS_PIPELINE);
388
389 assert(src_image->info.samples > 1);
390 if (src_image->info.samples <= 1) {
391 /* this causes GPU hangs if we get past here */
392 fprintf(stderr, "radv: Illegal resolve operation (src not multisampled), will hang GPU.");
393 return;
394 }
395 assert(dest_image->info.samples == 1);
396
397 if (src_image->info.samples >= 16) {
398 /* See commit aa3f9aaf31e9056a255f9e0472ebdfdaa60abe54 for the
399 * glBlitFramebuffer workaround for samples >= 16.
400 */
401 radv_finishme("vkCmdResolveImage: need interpolation workaround when "
402 "samples >= 16");
403 }
404
405 if (src_image->info.array_size > 1)
406 radv_finishme("vkCmdResolveImage: multisample array images");
407
408 if (dest_image->surface.dcc_size) {
409 radv_initialize_dcc(cmd_buffer, dest_image, 0xffffffff);
410 }
411 for (uint32_t r = 0; r < region_count; ++r) {
412 const VkImageResolve *region = &regions[r];
413
414 /* From the Vulkan 1.0 spec:
415 *
416 * - The aspectMask member of srcSubresource and dstSubresource must
417 * only contain VK_IMAGE_ASPECT_COLOR_BIT
418 *
419 * - The layerCount member of srcSubresource and dstSubresource must
420 * match
421 */
422 assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
423 assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
424 assert(region->srcSubresource.layerCount ==
425 region->dstSubresource.layerCount);
426
427 const uint32_t src_base_layer =
428 radv_meta_get_iview_layer(src_image, &region->srcSubresource,
429 &region->srcOffset);
430
431 const uint32_t dest_base_layer =
432 radv_meta_get_iview_layer(dest_image, &region->dstSubresource,
433 &region->dstOffset);
434
435 /**
436 * From Vulkan 1.0.6 spec: 18.6 Resolving Multisample Images
437 *
438 * extent is the size in texels of the source image to resolve in width,
439 * height and depth. 1D images use only x and width. 2D images use x, y,
440 * width and height. 3D images use x, y, z, width, height and depth.
441 *
442 * srcOffset and dstOffset select the initial x, y, and z offsets in
443 * texels of the sub-regions of the source and destination image data.
444 * extent is the size in texels of the source image to resolve in width,
445 * height and depth. 1D images use only x and width. 2D images use x, y,
446 * width and height. 3D images use x, y, z, width, height and depth.
447 */
448 const struct VkExtent3D extent =
449 radv_sanitize_image_extent(src_image->type, region->extent);
450 const struct VkOffset3D dstOffset =
451 radv_sanitize_image_offset(dest_image->type, region->dstOffset);
452
453
454 for (uint32_t layer = 0; layer < region->srcSubresource.layerCount;
455 ++layer) {
456
457 struct radv_image_view src_iview;
458 radv_image_view_init(&src_iview, cmd_buffer->device,
459 &(VkImageViewCreateInfo) {
460 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
461 .image = src_image_h,
462 .viewType = radv_meta_get_view_type(src_image),
463 .format = src_image->vk_format,
464 .subresourceRange = {
465 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
466 .baseMipLevel = region->srcSubresource.mipLevel,
467 .levelCount = 1,
468 .baseArrayLayer = src_base_layer + layer,
469 .layerCount = 1,
470 },
471 });
472
473 struct radv_image_view dest_iview;
474 radv_image_view_init(&dest_iview, cmd_buffer->device,
475 &(VkImageViewCreateInfo) {
476 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
477 .image = dest_image_h,
478 .viewType = radv_meta_get_view_type(dest_image),
479 .format = dest_image->vk_format,
480 .subresourceRange = {
481 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
482 .baseMipLevel = region->dstSubresource.mipLevel,
483 .levelCount = 1,
484 .baseArrayLayer = dest_base_layer + layer,
485 .layerCount = 1,
486 },
487 });
488
489 VkFramebuffer fb_h;
490 radv_CreateFramebuffer(device_h,
491 &(VkFramebufferCreateInfo) {
492 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
493 .attachmentCount = 2,
494 .pAttachments = (VkImageView[]) {
495 radv_image_view_to_handle(&src_iview),
496 radv_image_view_to_handle(&dest_iview),
497 },
498 .width = radv_minify(dest_image->info.width,
499 region->dstSubresource.mipLevel),
500 .height = radv_minify(dest_image->info.height,
501 region->dstSubresource.mipLevel),
502 .layers = 1
503 },
504 &cmd_buffer->pool->alloc,
505 &fb_h);
506
507 radv_CmdBeginRenderPass(cmd_buffer_h,
508 &(VkRenderPassBeginInfo) {
509 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
510 .renderPass = device->meta_state.resolve.pass,
511 .framebuffer = fb_h,
512 .renderArea = {
513 .offset = {
514 dstOffset.x,
515 dstOffset.y,
516 },
517 .extent = {
518 extent.width,
519 extent.height,
520 }
521 },
522 .clearValueCount = 0,
523 .pClearValues = NULL,
524 },
525 VK_SUBPASS_CONTENTS_INLINE);
526
527 emit_resolve(cmd_buffer,
528 &(VkOffset2D) {
529 .x = dstOffset.x,
530 .y = dstOffset.y,
531 },
532 &(VkExtent2D) {
533 .width = extent.width,
534 .height = extent.height,
535 });
536
537 radv_CmdEndRenderPass(cmd_buffer_h);
538
539 radv_DestroyFramebuffer(device_h, fb_h,
540 &cmd_buffer->pool->alloc);
541 }
542 }
543
544 radv_meta_restore(&saved_state, cmd_buffer);
545 }
546
547 /**
548 * Emit any needed resolves for the current subpass.
549 */
550 void
551 radv_cmd_buffer_resolve_subpass(struct radv_cmd_buffer *cmd_buffer)
552 {
553 struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
554 const struct radv_subpass *subpass = cmd_buffer->state.subpass;
555 struct radv_meta_saved_state saved_state;
556 enum radv_resolve_method resolve_method = RESOLVE_HW;
557
558 /* FINISHME(perf): Skip clears for resolve attachments.
559 *
560 * From the Vulkan 1.0 spec:
561 *
562 * If the first use of an attachment in a render pass is as a resolve
563 * attachment, then the loadOp is effectively ignored as the resolve is
564 * guaranteed to overwrite all pixels in the render area.
565 */
566
567 if (!subpass->has_resolve)
568 return;
569
570 for (uint32_t i = 0; i < subpass->color_count; ++i) {
571 VkAttachmentReference src_att = subpass->color_attachments[i];
572 VkAttachmentReference dest_att = subpass->resolve_attachments[i];
573
574 if (src_att.attachment == VK_ATTACHMENT_UNUSED ||
575 dest_att.attachment == VK_ATTACHMENT_UNUSED)
576 continue;
577
578 struct radv_image *dst_img = cmd_buffer->state.framebuffer->attachments[dest_att.attachment].attachment->image;
579 struct radv_image *src_img = cmd_buffer->state.framebuffer->attachments[src_att.attachment].attachment->image;
580
581 radv_pick_resolve_method_images(dst_img, src_img, &resolve_method);
582 if (resolve_method == RESOLVE_FRAGMENT) {
583 break;
584 }
585 }
586
587 if (resolve_method == RESOLVE_COMPUTE) {
588 radv_cmd_buffer_resolve_subpass_cs(cmd_buffer);
589 return;
590 } else if (resolve_method == RESOLVE_FRAGMENT) {
591 radv_cmd_buffer_resolve_subpass_fs(cmd_buffer);
592 return;
593 }
594
595 radv_meta_save(&saved_state, cmd_buffer,
596 RADV_META_SAVE_GRAPHICS_PIPELINE);
597
598 for (uint32_t i = 0; i < subpass->color_count; ++i) {
599 VkAttachmentReference src_att = subpass->color_attachments[i];
600 VkAttachmentReference dest_att = subpass->resolve_attachments[i];
601
602 if (src_att.attachment == VK_ATTACHMENT_UNUSED ||
603 dest_att.attachment == VK_ATTACHMENT_UNUSED)
604 continue;
605
606 struct radv_image *dst_img = cmd_buffer->state.framebuffer->attachments[dest_att.attachment].attachment->image;
607
608 if (dst_img->surface.dcc_size) {
609 radv_initialize_dcc(cmd_buffer, dst_img, 0xffffffff);
610 cmd_buffer->state.attachments[dest_att.attachment].current_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
611 }
612
613 struct radv_subpass resolve_subpass = {
614 .color_count = 2,
615 .color_attachments = (VkAttachmentReference[]) { src_att, dest_att },
616 .depth_stencil_attachment = { .attachment = VK_ATTACHMENT_UNUSED },
617 };
618
619 radv_cmd_buffer_set_subpass(cmd_buffer, &resolve_subpass, false);
620
621 emit_resolve(cmd_buffer,
622 &(VkOffset2D) { 0, 0 },
623 &(VkExtent2D) { fb->width, fb->height });
624 }
625
626 cmd_buffer->state.subpass = subpass;
627 radv_meta_restore(&saved_state, cmd_buffer);
628 }