101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2016 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include <assert.h>
2501e04c3fSmrg#include <stdbool.h>
2601e04c3fSmrg
277ec681f3Smrg#include "nir/nir_builder.h"
2801e04c3fSmrg#include "radv_meta.h"
2901e04c3fSmrg#include "radv_private.h"
3001e04c3fSmrg#include "sid.h"
317ec681f3Smrg#include "vk_format.h"
3201e04c3fSmrg
3301e04c3fSmrg/* emit 0, 0, 0, 1 */
3401e04c3fSmrgstatic nir_shader *
3501e04c3fSmrgbuild_nir_fs(void)
3601e04c3fSmrg{
377ec681f3Smrg   const struct glsl_type *vec4 = glsl_vec4_type();
387ec681f3Smrg   nir_variable *f_color; /* vec4, fragment output color */
3901e04c3fSmrg
407ec681f3Smrg   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, NULL, "meta_resolve_fs");
4101e04c3fSmrg
427ec681f3Smrg   f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4, "f_color");
437ec681f3Smrg   f_color->data.location = FRAG_RESULT_DATA0;
447ec681f3Smrg   nir_store_var(&b, f_color, nir_imm_vec4(&b, 0.0, 0.0, 0.0, 1.0), 0xf);
4501e04c3fSmrg
467ec681f3Smrg   return b.shader;
4701e04c3fSmrg}
4801e04c3fSmrg
4901e04c3fSmrgstatic VkResult
5001e04c3fSmrgcreate_pass(struct radv_device *device, VkFormat vk_format, VkRenderPass *pass)
5101e04c3fSmrg{
527ec681f3Smrg   VkResult result;
537ec681f3Smrg   VkDevice device_h = radv_device_to_handle(device);
547ec681f3Smrg   const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
557ec681f3Smrg   VkAttachmentDescription2 attachments[2];
567ec681f3Smrg   int i;
577ec681f3Smrg
587ec681f3Smrg   for (i = 0; i < 2; i++) {
597ec681f3Smrg      attachments[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
607ec681f3Smrg      attachments[i].pNext = NULL;
617ec681f3Smrg      attachments[i].format = vk_format;
627ec681f3Smrg      attachments[i].samples = 1;
637ec681f3Smrg      attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
647ec681f3Smrg      attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
657ec681f3Smrg   }
667ec681f3Smrg   attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
677ec681f3Smrg   attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
687ec681f3Smrg   attachments[1].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
697ec681f3Smrg   attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
707ec681f3Smrg
717ec681f3Smrg   result = radv_CreateRenderPass2(
727ec681f3Smrg      device_h,
737ec681f3Smrg      &(VkRenderPassCreateInfo2){
747ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
757ec681f3Smrg         .attachmentCount = 2,
767ec681f3Smrg         .pAttachments = attachments,
777ec681f3Smrg         .subpassCount = 1,
787ec681f3Smrg         .pSubpasses =
797ec681f3Smrg            &(VkSubpassDescription2){
807ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,
817ec681f3Smrg               .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
827ec681f3Smrg               .inputAttachmentCount = 0,
837ec681f3Smrg               .colorAttachmentCount = 2,
847ec681f3Smrg               .pColorAttachments =
857ec681f3Smrg                  (VkAttachmentReference2[]){
867ec681f3Smrg                     {
877ec681f3Smrg                        .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
887ec681f3Smrg                        .attachment = 0,
897ec681f3Smrg                        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
907ec681f3Smrg                     },
917ec681f3Smrg                     {
927ec681f3Smrg                        .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
937ec681f3Smrg                        .attachment = 1,
947ec681f3Smrg                        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
957ec681f3Smrg                     },
967ec681f3Smrg                  },
977ec681f3Smrg               .pResolveAttachments = NULL,
987ec681f3Smrg               .pDepthStencilAttachment =
997ec681f3Smrg                  &(VkAttachmentReference2){
1007ec681f3Smrg                     .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
1017ec681f3Smrg                     .attachment = VK_ATTACHMENT_UNUSED,
1027ec681f3Smrg                  },
1037ec681f3Smrg               .preserveAttachmentCount = 0,
1047ec681f3Smrg               .pPreserveAttachments = NULL,
1057ec681f3Smrg            },
1067ec681f3Smrg         .dependencyCount = 2,
1077ec681f3Smrg         .pDependencies =
1087ec681f3Smrg            (VkSubpassDependency2[]){{.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
1097ec681f3Smrg                                      .srcSubpass = VK_SUBPASS_EXTERNAL,
1107ec681f3Smrg                                      .dstSubpass = 0,
1117ec681f3Smrg                                      .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1127ec681f3Smrg                                      .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1137ec681f3Smrg                                      .srcAccessMask = 0,
1147ec681f3Smrg                                      .dstAccessMask = 0,
1157ec681f3Smrg                                      .dependencyFlags = 0},
1167ec681f3Smrg                                     {.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
1177ec681f3Smrg                                      .srcSubpass = 0,
1187ec681f3Smrg                                      .dstSubpass = VK_SUBPASS_EXTERNAL,
1197ec681f3Smrg                                      .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1207ec681f3Smrg                                      .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1217ec681f3Smrg                                      .srcAccessMask = 0,
1227ec681f3Smrg                                      .dstAccessMask = 0,
1237ec681f3Smrg                                      .dependencyFlags = 0}},
1247ec681f3Smrg      },
1257ec681f3Smrg      alloc, pass);
1267ec681f3Smrg
1277ec681f3Smrg   return result;
12801e04c3fSmrg}
12901e04c3fSmrg
13001e04c3fSmrgstatic VkResult
1317ec681f3Smrgcreate_pipeline(struct radv_device *device, VkShaderModule vs_module_h, VkPipeline *pipeline,
1327ec681f3Smrg                VkRenderPass pass)
13301e04c3fSmrg{
1347ec681f3Smrg   VkResult result;
1357ec681f3Smrg   VkDevice device_h = radv_device_to_handle(device);
1367ec681f3Smrg
1377ec681f3Smrg   nir_shader *fs_module = build_nir_fs();
1387ec681f3Smrg   if (!fs_module) {
1397ec681f3Smrg      /* XXX: Need more accurate error */
1407ec681f3Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1417ec681f3Smrg      goto cleanup;
1427ec681f3Smrg   }
1437ec681f3Smrg
1447ec681f3Smrg   VkPipelineLayoutCreateInfo pl_create_info = {
1457ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1467ec681f3Smrg      .setLayoutCount = 0,
1477ec681f3Smrg      .pSetLayouts = NULL,
1487ec681f3Smrg      .pushConstantRangeCount = 0,
1497ec681f3Smrg      .pPushConstantRanges = NULL,
1507ec681f3Smrg   };
1517ec681f3Smrg
1527ec681f3Smrg   if (!device->meta_state.resolve.p_layout) {
1537ec681f3Smrg      result =
1547ec681f3Smrg         radv_CreatePipelineLayout(radv_device_to_handle(device), &pl_create_info,
1557ec681f3Smrg                                   &device->meta_state.alloc, &device->meta_state.resolve.p_layout);
1567ec681f3Smrg      if (result != VK_SUCCESS)
1577ec681f3Smrg         goto cleanup;
1587ec681f3Smrg   }
1597ec681f3Smrg
1607ec681f3Smrg   result = radv_graphics_pipeline_create(
1617ec681f3Smrg      device_h, radv_pipeline_cache_to_handle(&device->meta_state.cache),
1627ec681f3Smrg      &(VkGraphicsPipelineCreateInfo){
1637ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1647ec681f3Smrg         .stageCount = 2,
1657ec681f3Smrg         .pStages =
1667ec681f3Smrg            (VkPipelineShaderStageCreateInfo[]){
1677ec681f3Smrg               {
1687ec681f3Smrg                  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1697ec681f3Smrg                  .stage = VK_SHADER_STAGE_VERTEX_BIT,
1707ec681f3Smrg                  .module = vs_module_h,
1717ec681f3Smrg                  .pName = "main",
1727ec681f3Smrg               },
1737ec681f3Smrg               {
1747ec681f3Smrg                  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1757ec681f3Smrg                  .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
1767ec681f3Smrg                  .module = vk_shader_module_handle_from_nir(fs_module),
1777ec681f3Smrg                  .pName = "main",
1787ec681f3Smrg               },
1797ec681f3Smrg            },
1807ec681f3Smrg         .pVertexInputState =
1817ec681f3Smrg            &(VkPipelineVertexInputStateCreateInfo){
1827ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1837ec681f3Smrg               .vertexBindingDescriptionCount = 0,
1847ec681f3Smrg               .vertexAttributeDescriptionCount = 0,
1857ec681f3Smrg            },
1867ec681f3Smrg         .pInputAssemblyState =
1877ec681f3Smrg            &(VkPipelineInputAssemblyStateCreateInfo){
1887ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1897ec681f3Smrg               .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1907ec681f3Smrg               .primitiveRestartEnable = false,
1917ec681f3Smrg            },
1927ec681f3Smrg         .pViewportState =
1937ec681f3Smrg            &(VkPipelineViewportStateCreateInfo){
1947ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1957ec681f3Smrg               .viewportCount = 1,
1967ec681f3Smrg               .scissorCount = 1,
1977ec681f3Smrg            },
1987ec681f3Smrg         .pRasterizationState =
1997ec681f3Smrg            &(VkPipelineRasterizationStateCreateInfo){
2007ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
2017ec681f3Smrg               .depthClampEnable = false,
2027ec681f3Smrg               .rasterizerDiscardEnable = false,
2037ec681f3Smrg               .polygonMode = VK_POLYGON_MODE_FILL,
2047ec681f3Smrg               .cullMode = VK_CULL_MODE_NONE,
2057ec681f3Smrg               .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
2067ec681f3Smrg            },
2077ec681f3Smrg         .pMultisampleState =
2087ec681f3Smrg            &(VkPipelineMultisampleStateCreateInfo){
2097ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
2107ec681f3Smrg               .rasterizationSamples = 1,
2117ec681f3Smrg               .sampleShadingEnable = false,
2127ec681f3Smrg               .pSampleMask = NULL,
2137ec681f3Smrg               .alphaToCoverageEnable = false,
2147ec681f3Smrg               .alphaToOneEnable = false,
2157ec681f3Smrg            },
2167ec681f3Smrg         .pColorBlendState =
2177ec681f3Smrg            &(VkPipelineColorBlendStateCreateInfo){
2187ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
2197ec681f3Smrg               .logicOpEnable = false,
2207ec681f3Smrg               .attachmentCount = 2,
2217ec681f3Smrg               .pAttachments =
2227ec681f3Smrg                  (VkPipelineColorBlendAttachmentState[]){
2237ec681f3Smrg                     {
2247ec681f3Smrg                        .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
2257ec681f3Smrg                                          VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
2267ec681f3Smrg                     },
2277ec681f3Smrg                     {
2287ec681f3Smrg                        .colorWriteMask = 0,
2297ec681f3Smrg
2307ec681f3Smrg                     }},
2317ec681f3Smrg            },
2327ec681f3Smrg         .pDynamicState =
2337ec681f3Smrg            &(VkPipelineDynamicStateCreateInfo){
2347ec681f3Smrg               .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
2357ec681f3Smrg               .dynamicStateCount = 2,
2367ec681f3Smrg               .pDynamicStates =
2377ec681f3Smrg                  (VkDynamicState[]){
2387ec681f3Smrg                     VK_DYNAMIC_STATE_VIEWPORT,
2397ec681f3Smrg                     VK_DYNAMIC_STATE_SCISSOR,
2407ec681f3Smrg                  },
2417ec681f3Smrg            },
2427ec681f3Smrg         .layout = device->meta_state.resolve.p_layout,
2437ec681f3Smrg         .renderPass = pass,
2447ec681f3Smrg         .subpass = 0,
2457ec681f3Smrg      },
2467ec681f3Smrg      &(struct radv_graphics_pipeline_create_info){
2477ec681f3Smrg         .use_rectlist = true,
2487ec681f3Smrg         .custom_blend_mode = V_028808_CB_RESOLVE,
2497ec681f3Smrg      },
2507ec681f3Smrg      &device->meta_state.alloc, pipeline);
2517ec681f3Smrg   if (result != VK_SUCCESS)
2527ec681f3Smrg      goto cleanup;
2537ec681f3Smrg
2547ec681f3Smrg   goto cleanup;
25501e04c3fSmrg
25601e04c3fSmrgcleanup:
2577ec681f3Smrg   ralloc_free(fs_module);
2587ec681f3Smrg   return result;
25901e04c3fSmrg}
26001e04c3fSmrg
26101e04c3fSmrgvoid
26201e04c3fSmrgradv_device_finish_meta_resolve_state(struct radv_device *device)
26301e04c3fSmrg{
2647ec681f3Smrg   struct radv_meta_state *state = &device->meta_state;
2657ec681f3Smrg
2667ec681f3Smrg   for (uint32_t j = 0; j < NUM_META_FS_KEYS; j++) {
2677ec681f3Smrg      radv_DestroyRenderPass(radv_device_to_handle(device), state->resolve.pass[j], &state->alloc);
2687ec681f3Smrg      radv_DestroyPipeline(radv_device_to_handle(device), state->resolve.pipeline[j],
2697ec681f3Smrg                           &state->alloc);
2707ec681f3Smrg   }
2717ec681f3Smrg   radv_DestroyPipelineLayout(radv_device_to_handle(device), state->resolve.p_layout,
2727ec681f3Smrg                              &state->alloc);
27301e04c3fSmrg}
27401e04c3fSmrg
27501e04c3fSmrgVkResult
27601e04c3fSmrgradv_device_init_meta_resolve_state(struct radv_device *device, bool on_demand)
27701e04c3fSmrg{
2787ec681f3Smrg   if (on_demand)
2797ec681f3Smrg      return VK_SUCCESS;
2807ec681f3Smrg
2817ec681f3Smrg   VkResult res = VK_SUCCESS;
2827ec681f3Smrg   struct radv_meta_state *state = &device->meta_state;
2837ec681f3Smrg   nir_shader *vs_module = radv_meta_build_nir_vs_generate_vertices();
2847ec681f3Smrg   if (!vs_module) {
2857ec681f3Smrg      /* XXX: Need more accurate error */
2867ec681f3Smrg      res = VK_ERROR_OUT_OF_HOST_MEMORY;
2877ec681f3Smrg      goto fail;
2887ec681f3Smrg   }
2897ec681f3Smrg
2907ec681f3Smrg   for (uint32_t i = 0; i < NUM_META_FS_KEYS; ++i) {
2917ec681f3Smrg      VkFormat format = radv_fs_key_format_exemplars[i];
2927ec681f3Smrg      unsigned fs_key = radv_format_meta_fs_key(device, format);
2937ec681f3Smrg      res = create_pass(device, format, &state->resolve.pass[fs_key]);
2947ec681f3Smrg      if (res != VK_SUCCESS)
2957ec681f3Smrg         goto fail;
2967ec681f3Smrg
2977ec681f3Smrg      VkShaderModule vs_module_h = vk_shader_module_handle_from_nir(vs_module);
2987ec681f3Smrg      res = create_pipeline(device, vs_module_h, &state->resolve.pipeline[fs_key],
2997ec681f3Smrg                            state->resolve.pass[fs_key]);
3007ec681f3Smrg      if (res != VK_SUCCESS)
3017ec681f3Smrg         goto fail;
3027ec681f3Smrg   }
3037ec681f3Smrg
3047ec681f3Smrg   goto cleanup;
30501e04c3fSmrg
30601e04c3fSmrgfail:
3077ec681f3Smrg   radv_device_finish_meta_resolve_state(device);
30801e04c3fSmrg
30901e04c3fSmrgcleanup:
3107ec681f3Smrg   ralloc_free(vs_module);
31101e04c3fSmrg
3127ec681f3Smrg   return res;
31301e04c3fSmrg}
31401e04c3fSmrg
31501e04c3fSmrgstatic void
3167ec681f3Smrgemit_resolve(struct radv_cmd_buffer *cmd_buffer, const struct radv_image *src_image,
3177ec681f3Smrg             const struct radv_image *dst_image, VkFormat vk_format, const VkOffset2D *dest_offset,
31801e04c3fSmrg             const VkExtent2D *resolve_extent)
31901e04c3fSmrg{
3207ec681f3Smrg   struct radv_device *device = cmd_buffer->device;
3217ec681f3Smrg   VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
3227ec681f3Smrg   unsigned fs_key = radv_format_meta_fs_key(device, vk_format);
3237ec681f3Smrg
3247ec681f3Smrg   cmd_buffer->state.flush_bits |=
3257ec681f3Smrg      radv_src_access_flush(cmd_buffer, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, src_image) |
3267ec681f3Smrg      radv_dst_access_flush(cmd_buffer, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, src_image) |
3277ec681f3Smrg      radv_dst_access_flush(cmd_buffer, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, dst_image);
3287ec681f3Smrg
3297ec681f3Smrg   radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
3307ec681f3Smrg                        device->meta_state.resolve.pipeline[fs_key]);
3317ec681f3Smrg
3327ec681f3Smrg   radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1,
3337ec681f3Smrg                       &(VkViewport){.x = dest_offset->x,
3347ec681f3Smrg                                     .y = dest_offset->y,
3357ec681f3Smrg                                     .width = resolve_extent->width,
3367ec681f3Smrg                                     .height = resolve_extent->height,
3377ec681f3Smrg                                     .minDepth = 0.0f,
3387ec681f3Smrg                                     .maxDepth = 1.0f});
3397ec681f3Smrg
3407ec681f3Smrg   radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1,
3417ec681f3Smrg                      &(VkRect2D){
3427ec681f3Smrg                         .offset = *dest_offset,
3437ec681f3Smrg                         .extent = *resolve_extent,
3447ec681f3Smrg                      });
3457ec681f3Smrg
3467ec681f3Smrg   radv_CmdDraw(cmd_buffer_h, 3, 1, 0, 0);
3477ec681f3Smrg   cmd_buffer->state.flush_bits |=
3487ec681f3Smrg      radv_src_access_flush(cmd_buffer, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, dst_image);
34901e04c3fSmrg}
35001e04c3fSmrg
35101e04c3fSmrgenum radv_resolve_method {
3527ec681f3Smrg   RESOLVE_HW,
3537ec681f3Smrg   RESOLVE_COMPUTE,
3547ec681f3Smrg   RESOLVE_FRAGMENT,
35501e04c3fSmrg};
35601e04c3fSmrg
3577ec681f3Smrgstatic bool
3587ec681f3Smrgimage_hw_resolve_compat(const struct radv_device *device, struct radv_image *src_image,
3597ec681f3Smrg                        struct radv_image *dst_image)
3607ec681f3Smrg{
3617ec681f3Smrg   if (device->physical_device->rad_info.chip_class >= GFX9) {
3627ec681f3Smrg      return dst_image->planes[0].surface.u.gfx9.swizzle_mode ==
3637ec681f3Smrg             src_image->planes[0].surface.u.gfx9.swizzle_mode;
3647ec681f3Smrg   } else {
3657ec681f3Smrg      return dst_image->planes[0].surface.micro_tile_mode ==
3667ec681f3Smrg             src_image->planes[0].surface.micro_tile_mode;
3677ec681f3Smrg   }
3687ec681f3Smrg}
3697ec681f3Smrg
3707ec681f3Smrgstatic void
3717ec681f3Smrgradv_pick_resolve_method_images(struct radv_device *device, struct radv_image *src_image,
3727ec681f3Smrg                                VkFormat src_format, struct radv_image *dest_image,
3737ec681f3Smrg                                unsigned dest_level, VkImageLayout dest_image_layout,
3747ec681f3Smrg                                bool dest_render_loop, struct radv_cmd_buffer *cmd_buffer,
3757ec681f3Smrg                                enum radv_resolve_method *method)
37601e04c3fSmrg
37701e04c3fSmrg{
3787ec681f3Smrg   uint32_t queue_mask = radv_image_queue_family_mask(dest_image, cmd_buffer->queue_family_index,
3797ec681f3Smrg                                                      cmd_buffer->queue_family_index);
3807ec681f3Smrg
3817ec681f3Smrg   if (vk_format_is_color(src_format)) {
3827ec681f3Smrg      /* Using the fragment resolve path is currently a hint to
3837ec681f3Smrg       * avoid decompressing DCC for partial resolves and
3847ec681f3Smrg       * re-initialize it after resolving using compute.
3857ec681f3Smrg       * TODO: Add support for layered and int to the fragment path.
3867ec681f3Smrg       */
3877ec681f3Smrg      if (radv_layout_dcc_compressed(device, dest_image, dest_level, dest_image_layout,
3887ec681f3Smrg                                     dest_render_loop, queue_mask)) {
3897ec681f3Smrg         *method = RESOLVE_FRAGMENT;
3907ec681f3Smrg      } else if (!image_hw_resolve_compat(device, src_image, dest_image)) {
3917ec681f3Smrg         /* The micro tile mode only needs to match for the HW
3927ec681f3Smrg          * resolve path which is the default path for non-DCC
3937ec681f3Smrg          * resolves.
3947ec681f3Smrg          */
3957ec681f3Smrg         *method = RESOLVE_COMPUTE;
3967ec681f3Smrg      }
3977ec681f3Smrg
3987ec681f3Smrg      if (src_format == VK_FORMAT_R16G16_UNORM || src_format == VK_FORMAT_R16G16_SNORM)
3997ec681f3Smrg         *method = RESOLVE_COMPUTE;
4007ec681f3Smrg      else if (vk_format_is_int(src_format))
4017ec681f3Smrg         *method = RESOLVE_COMPUTE;
4027ec681f3Smrg      else if (src_image->info.array_size > 1 || dest_image->info.array_size > 1)
4037ec681f3Smrg         *method = RESOLVE_COMPUTE;
4047ec681f3Smrg   } else {
4057ec681f3Smrg      if (src_image->info.array_size > 1 || dest_image->info.array_size > 1)
4067ec681f3Smrg         *method = RESOLVE_COMPUTE;
4077ec681f3Smrg      else
4087ec681f3Smrg         *method = RESOLVE_FRAGMENT;
4097ec681f3Smrg   }
41001e04c3fSmrg}
41101e04c3fSmrg
41201e04c3fSmrgstatic VkResult
4137ec681f3Smrgbuild_resolve_pipeline(struct radv_device *device, unsigned fs_key)
41401e04c3fSmrg{
4157ec681f3Smrg   VkResult result = VK_SUCCESS;
41601e04c3fSmrg
4177ec681f3Smrg   if (device->meta_state.resolve.pipeline[fs_key])
4187ec681f3Smrg      return result;
41901e04c3fSmrg
4207ec681f3Smrg   mtx_lock(&device->meta_state.mtx);
4217ec681f3Smrg   if (device->meta_state.resolve.pipeline[fs_key]) {
4227ec681f3Smrg      mtx_unlock(&device->meta_state.mtx);
4237ec681f3Smrg      return result;
4247ec681f3Smrg   }
42501e04c3fSmrg
4267ec681f3Smrg   nir_shader *vs_module = radv_meta_build_nir_vs_generate_vertices();
42701e04c3fSmrg
4287ec681f3Smrg   result = create_pass(device, radv_fs_key_format_exemplars[fs_key],
4297ec681f3Smrg                        &device->meta_state.resolve.pass[fs_key]);
4307ec681f3Smrg   if (result != VK_SUCCESS)
4317ec681f3Smrg      goto fail;
43201e04c3fSmrg
4337ec681f3Smrg   VkShaderModule vs_module_h = vk_shader_module_handle_from_nir(vs_module);
4347ec681f3Smrg   result = create_pipeline(device, vs_module_h, &device->meta_state.resolve.pipeline[fs_key],
4357ec681f3Smrg                            device->meta_state.resolve.pass[fs_key]);
43601e04c3fSmrg
43701e04c3fSmrgfail:
4387ec681f3Smrg   ralloc_free(vs_module);
4397ec681f3Smrg   mtx_unlock(&device->meta_state.mtx);
4407ec681f3Smrg   return result;
44101e04c3fSmrg}
44201e04c3fSmrg
4437ec681f3Smrgstatic void
4447ec681f3Smrgradv_meta_resolve_hardware_image(struct radv_cmd_buffer *cmd_buffer, struct radv_image *src_image,
4457ec681f3Smrg                                 VkImageLayout src_image_layout, struct radv_image *dst_image,
4467ec681f3Smrg                                 VkImageLayout dst_image_layout, const VkImageResolve2KHR *region)
4477ec681f3Smrg{
4487ec681f3Smrg   struct radv_device *device = cmd_buffer->device;
4497ec681f3Smrg   struct radv_meta_saved_state saved_state;
4507ec681f3Smrg
4517ec681f3Smrg   radv_meta_save(&saved_state, cmd_buffer, RADV_META_SAVE_GRAPHICS_PIPELINE);
4527ec681f3Smrg
4537ec681f3Smrg   assert(src_image->info.samples > 1);
4547ec681f3Smrg   assert(dst_image->info.samples == 1);
4557ec681f3Smrg
4567ec681f3Smrg   unsigned fs_key = radv_format_meta_fs_key(device, dst_image->vk_format);
4577ec681f3Smrg
4587ec681f3Smrg   /* From the Vulkan 1.0 spec:
4597ec681f3Smrg    *
4607ec681f3Smrg    *    - The aspectMask member of srcSubresource and dstSubresource must
4617ec681f3Smrg    *      only contain VK_IMAGE_ASPECT_COLOR_BIT
4627ec681f3Smrg    *
4637ec681f3Smrg    *    - The layerCount member of srcSubresource and dstSubresource must
4647ec681f3Smrg    *      match
4657ec681f3Smrg    */
4667ec681f3Smrg   assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
4677ec681f3Smrg   assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
4687ec681f3Smrg   assert(region->srcSubresource.layerCount == region->dstSubresource.layerCount);
4697ec681f3Smrg
4707ec681f3Smrg   const uint32_t src_base_layer =
4717ec681f3Smrg      radv_meta_get_iview_layer(src_image, &region->srcSubresource, &region->srcOffset);
4727ec681f3Smrg
4737ec681f3Smrg   const uint32_t dst_base_layer =
4747ec681f3Smrg      radv_meta_get_iview_layer(dst_image, &region->dstSubresource, &region->dstOffset);
4757ec681f3Smrg
4767ec681f3Smrg   /**
4777ec681f3Smrg    * From Vulkan 1.0.6 spec: 18.6 Resolving Multisample Images
4787ec681f3Smrg    *
4797ec681f3Smrg    *    extent is the size in texels of the source image to resolve in width,
4807ec681f3Smrg    *    height and depth. 1D images use only x and width. 2D images use x, y,
4817ec681f3Smrg    *    width and height. 3D images use x, y, z, width, height and depth.
4827ec681f3Smrg    *
4837ec681f3Smrg    *    srcOffset and dstOffset select the initial x, y, and z offsets in
4847ec681f3Smrg    *    texels of the sub-regions of the source and destination image data.
4857ec681f3Smrg    *    extent is the size in texels of the source image to resolve in width,
4867ec681f3Smrg    *    height and depth. 1D images use only x and width. 2D images use x, y,
4877ec681f3Smrg    *    width and height. 3D images use x, y, z, width, height and depth.
4887ec681f3Smrg    */
4897ec681f3Smrg   const struct VkExtent3D extent = radv_sanitize_image_extent(src_image->type, region->extent);
4907ec681f3Smrg   const struct VkOffset3D dstOffset =
4917ec681f3Smrg      radv_sanitize_image_offset(dst_image->type, region->dstOffset);
4927ec681f3Smrg
4937ec681f3Smrg   uint32_t queue_mask = radv_image_queue_family_mask(dst_image, cmd_buffer->queue_family_index,
4947ec681f3Smrg                                                      cmd_buffer->queue_family_index);
4957ec681f3Smrg
4967ec681f3Smrg   if (radv_layout_dcc_compressed(cmd_buffer->device, dst_image, region->dstSubresource.mipLevel,
4977ec681f3Smrg                                  dst_image_layout, false, queue_mask)) {
4987ec681f3Smrg      VkImageSubresourceRange range = {
4997ec681f3Smrg         .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5007ec681f3Smrg         .baseMipLevel = region->dstSubresource.mipLevel,
5017ec681f3Smrg         .levelCount = 1,
5027ec681f3Smrg         .baseArrayLayer = dst_base_layer,
5037ec681f3Smrg         .layerCount = region->dstSubresource.layerCount,
5047ec681f3Smrg      };
5057ec681f3Smrg
5067ec681f3Smrg      cmd_buffer->state.flush_bits |= radv_init_dcc(cmd_buffer, dst_image, &range, 0xffffffff);
5077ec681f3Smrg   }
5087ec681f3Smrg
5097ec681f3Smrg   for (uint32_t layer = 0; layer < region->srcSubresource.layerCount; ++layer) {
5107ec681f3Smrg
5117ec681f3Smrg      VkResult ret = build_resolve_pipeline(device, fs_key);
5127ec681f3Smrg      if (ret != VK_SUCCESS) {
5137ec681f3Smrg         cmd_buffer->record_result = ret;
5147ec681f3Smrg         break;
5157ec681f3Smrg      }
5167ec681f3Smrg
5177ec681f3Smrg      struct radv_image_view src_iview;
5187ec681f3Smrg      radv_image_view_init(&src_iview, cmd_buffer->device,
5197ec681f3Smrg                           &(VkImageViewCreateInfo){
5207ec681f3Smrg                              .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
5217ec681f3Smrg                              .image = radv_image_to_handle(src_image),
5227ec681f3Smrg                              .viewType = radv_meta_get_view_type(src_image),
5237ec681f3Smrg                              .format = src_image->vk_format,
5247ec681f3Smrg                              .subresourceRange =
5257ec681f3Smrg                                 {
5267ec681f3Smrg                                    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5277ec681f3Smrg                                    .baseMipLevel = region->srcSubresource.mipLevel,
5287ec681f3Smrg                                    .levelCount = 1,
5297ec681f3Smrg                                    .baseArrayLayer = src_base_layer + layer,
5307ec681f3Smrg                                    .layerCount = 1,
5317ec681f3Smrg                                 },
5327ec681f3Smrg                           },
5337ec681f3Smrg                           NULL);
5347ec681f3Smrg
5357ec681f3Smrg      struct radv_image_view dst_iview;
5367ec681f3Smrg      radv_image_view_init(&dst_iview, cmd_buffer->device,
5377ec681f3Smrg                           &(VkImageViewCreateInfo){
5387ec681f3Smrg                              .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
5397ec681f3Smrg                              .image = radv_image_to_handle(dst_image),
5407ec681f3Smrg                              .viewType = radv_meta_get_view_type(dst_image),
5417ec681f3Smrg                              .format = dst_image->vk_format,
5427ec681f3Smrg                              .subresourceRange =
5437ec681f3Smrg                                 {
5447ec681f3Smrg                                    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5457ec681f3Smrg                                    .baseMipLevel = region->dstSubresource.mipLevel,
5467ec681f3Smrg                                    .levelCount = 1,
5477ec681f3Smrg                                    .baseArrayLayer = dst_base_layer + layer,
5487ec681f3Smrg                                    .layerCount = 1,
5497ec681f3Smrg                                 },
5507ec681f3Smrg                           },
5517ec681f3Smrg                           NULL);
5527ec681f3Smrg
5537ec681f3Smrg      VkFramebuffer fb_h;
5547ec681f3Smrg      radv_CreateFramebuffer(
5557ec681f3Smrg         radv_device_to_handle(device),
5567ec681f3Smrg         &(VkFramebufferCreateInfo){
5577ec681f3Smrg            .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
5587ec681f3Smrg            .attachmentCount = 2,
5597ec681f3Smrg            .pAttachments =
5607ec681f3Smrg               (VkImageView[]){
5617ec681f3Smrg                  radv_image_view_to_handle(&src_iview),
5627ec681f3Smrg                  radv_image_view_to_handle(&dst_iview),
5637ec681f3Smrg               },
5647ec681f3Smrg            .width = radv_minify(dst_image->info.width, region->dstSubresource.mipLevel),
5657ec681f3Smrg            .height = radv_minify(dst_image->info.height, region->dstSubresource.mipLevel),
5667ec681f3Smrg            .layers = 1},
5677ec681f3Smrg         &cmd_buffer->pool->alloc, &fb_h);
5687ec681f3Smrg
5697ec681f3Smrg      radv_cmd_buffer_begin_render_pass(cmd_buffer,
5707ec681f3Smrg                                        &(VkRenderPassBeginInfo){
5717ec681f3Smrg                                           .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
5727ec681f3Smrg                                           .renderPass = device->meta_state.resolve.pass[fs_key],
5737ec681f3Smrg                                           .framebuffer = fb_h,
5747ec681f3Smrg                                           .renderArea = {.offset =
5757ec681f3Smrg                                                             {
5767ec681f3Smrg                                                                dstOffset.x,
5777ec681f3Smrg                                                                dstOffset.y,
5787ec681f3Smrg                                                             },
5797ec681f3Smrg                                                          .extent =
5807ec681f3Smrg                                                             {
5817ec681f3Smrg                                                                extent.width,
5827ec681f3Smrg                                                                extent.height,
5837ec681f3Smrg                                                             }},
5847ec681f3Smrg                                           .clearValueCount = 0,
5857ec681f3Smrg                                           .pClearValues = NULL,
5867ec681f3Smrg                                        },
5877ec681f3Smrg                                        NULL);
5887ec681f3Smrg
5897ec681f3Smrg      radv_cmd_buffer_set_subpass(cmd_buffer, &cmd_buffer->state.pass->subpasses[0]);
5907ec681f3Smrg
5917ec681f3Smrg      emit_resolve(cmd_buffer, src_image, dst_image, dst_iview.vk_format,
5927ec681f3Smrg                   &(VkOffset2D){
5937ec681f3Smrg                      .x = dstOffset.x,
5947ec681f3Smrg                      .y = dstOffset.y,
5957ec681f3Smrg                   },
5967ec681f3Smrg                   &(VkExtent2D){
5977ec681f3Smrg                      .width = extent.width,
5987ec681f3Smrg                      .height = extent.height,
5997ec681f3Smrg                   });
6007ec681f3Smrg
6017ec681f3Smrg      radv_cmd_buffer_end_render_pass(cmd_buffer);
6027ec681f3Smrg
6037ec681f3Smrg      radv_image_view_finish(&src_iview);
6047ec681f3Smrg      radv_image_view_finish(&dst_iview);
6057ec681f3Smrg      radv_DestroyFramebuffer(radv_device_to_handle(device), fb_h, &cmd_buffer->pool->alloc);
6067ec681f3Smrg   }
6077ec681f3Smrg
6087ec681f3Smrg   radv_meta_restore(&saved_state, cmd_buffer);
6097ec681f3Smrg}
6107ec681f3Smrg
6117ec681f3Smrgstatic void
6127ec681f3Smrgresolve_image(struct radv_cmd_buffer *cmd_buffer, struct radv_image *src_image,
6137ec681f3Smrg              VkImageLayout src_image_layout, struct radv_image *dst_image,
6147ec681f3Smrg              VkImageLayout dst_image_layout, const VkImageResolve2KHR *region,
6157ec681f3Smrg              enum radv_resolve_method resolve_method)
61601e04c3fSmrg{
6177ec681f3Smrg   switch (resolve_method) {
6187ec681f3Smrg   case RESOLVE_HW:
6197ec681f3Smrg      radv_meta_resolve_hardware_image(cmd_buffer, src_image, src_image_layout, dst_image,
6207ec681f3Smrg                                       dst_image_layout, region);
6217ec681f3Smrg      break;
6227ec681f3Smrg   case RESOLVE_FRAGMENT:
6237ec681f3Smrg      radv_meta_resolve_fragment_image(cmd_buffer, src_image, src_image_layout, dst_image,
6247ec681f3Smrg                                       dst_image_layout, region);
6257ec681f3Smrg      break;
6267ec681f3Smrg   case RESOLVE_COMPUTE:
6277ec681f3Smrg      radv_meta_resolve_compute_image(cmd_buffer, src_image, src_image->vk_format, src_image_layout,
6287ec681f3Smrg                                      dst_image, dst_image->vk_format, dst_image_layout, region);
6297ec681f3Smrg      break;
6307ec681f3Smrg   default:
6317ec681f3Smrg      assert(!"Invalid resolve method selected");
6327ec681f3Smrg   }
6337ec681f3Smrg}
6347ec681f3Smrg
6357ec681f3Smrgvoid
6367ec681f3Smrgradv_CmdResolveImage2KHR(VkCommandBuffer commandBuffer,
6377ec681f3Smrg                         const VkResolveImageInfo2KHR *pResolveImageInfo)
6387ec681f3Smrg{
6397ec681f3Smrg   RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
6407ec681f3Smrg   RADV_FROM_HANDLE(radv_image, src_image, pResolveImageInfo->srcImage);
6417ec681f3Smrg   RADV_FROM_HANDLE(radv_image, dst_image, pResolveImageInfo->dstImage);
6427ec681f3Smrg   VkImageLayout src_image_layout = pResolveImageInfo->srcImageLayout;
6437ec681f3Smrg   VkImageLayout dst_image_layout = pResolveImageInfo->dstImageLayout;
6447ec681f3Smrg   enum radv_resolve_method resolve_method = RESOLVE_HW;
6457ec681f3Smrg   /* we can use the hw resolve only for single full resolves */
6467ec681f3Smrg   if (pResolveImageInfo->regionCount == 1) {
6477ec681f3Smrg      if (pResolveImageInfo->pRegions[0].srcOffset.x ||
6487ec681f3Smrg          pResolveImageInfo->pRegions[0].srcOffset.y || pResolveImageInfo->pRegions[0].srcOffset.z)
6497ec681f3Smrg         resolve_method = RESOLVE_COMPUTE;
6507ec681f3Smrg      if (pResolveImageInfo->pRegions[0].dstOffset.x ||
6517ec681f3Smrg          pResolveImageInfo->pRegions[0].dstOffset.y || pResolveImageInfo->pRegions[0].dstOffset.z)
6527ec681f3Smrg         resolve_method = RESOLVE_COMPUTE;
6537ec681f3Smrg
6547ec681f3Smrg      if (pResolveImageInfo->pRegions[0].extent.width != src_image->info.width ||
6557ec681f3Smrg          pResolveImageInfo->pRegions[0].extent.height != src_image->info.height ||
6567ec681f3Smrg          pResolveImageInfo->pRegions[0].extent.depth != src_image->info.depth)
6577ec681f3Smrg         resolve_method = RESOLVE_COMPUTE;
6587ec681f3Smrg   } else
6597ec681f3Smrg      resolve_method = RESOLVE_COMPUTE;
6607ec681f3Smrg
6617ec681f3Smrg   for (uint32_t r = 0; r < pResolveImageInfo->regionCount; r++) {
6627ec681f3Smrg      const VkImageResolve2KHR *region = &pResolveImageInfo->pRegions[r];
6637ec681f3Smrg
6647ec681f3Smrg      radv_pick_resolve_method_images(cmd_buffer->device, src_image, src_image->vk_format, dst_image,
6657ec681f3Smrg                                      region->dstSubresource.mipLevel, dst_image_layout, false,
6667ec681f3Smrg                                      cmd_buffer, &resolve_method);
6677ec681f3Smrg
6687ec681f3Smrg      resolve_image(cmd_buffer, src_image, src_image_layout, dst_image, dst_image_layout, region,
6697ec681f3Smrg                    resolve_method);
6707ec681f3Smrg   }
6717ec681f3Smrg}
6727ec681f3Smrg
6737ec681f3Smrgstatic void
6747ec681f3Smrgradv_cmd_buffer_resolve_subpass_hw(struct radv_cmd_buffer *cmd_buffer)
6757ec681f3Smrg{
6767ec681f3Smrg   struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
6777ec681f3Smrg   const struct radv_subpass *subpass = cmd_buffer->state.subpass;
6787ec681f3Smrg   struct radv_meta_saved_state saved_state;
6797ec681f3Smrg
6807ec681f3Smrg   radv_meta_save(&saved_state, cmd_buffer, RADV_META_SAVE_GRAPHICS_PIPELINE);
6817ec681f3Smrg
6827ec681f3Smrg   for (uint32_t i = 0; i < subpass->color_count; ++i) {
6837ec681f3Smrg      struct radv_subpass_attachment src_att = subpass->color_attachments[i];
6847ec681f3Smrg      struct radv_subpass_attachment dest_att = subpass->resolve_attachments[i];
6857ec681f3Smrg
6867ec681f3Smrg      if (dest_att.attachment == VK_ATTACHMENT_UNUSED)
6877ec681f3Smrg         continue;
6887ec681f3Smrg
6897ec681f3Smrg      struct radv_image_view *src_iview = cmd_buffer->state.attachments[src_att.attachment].iview;
6907ec681f3Smrg      struct radv_image *src_img = src_iview->image;
6917ec681f3Smrg
6927ec681f3Smrg      struct radv_image_view *dest_iview = cmd_buffer->state.attachments[dest_att.attachment].iview;
6937ec681f3Smrg      struct radv_image *dst_img = dest_iview->image;
6947ec681f3Smrg      VkImageLayout dst_image_layout = cmd_buffer->state.attachments[dest_att.attachment].current_layout;
6957ec681f3Smrg
6967ec681f3Smrg      uint32_t queue_mask = radv_image_queue_family_mask(dst_img, cmd_buffer->queue_family_index,
6977ec681f3Smrg                                                         cmd_buffer->queue_family_index);
6987ec681f3Smrg
6997ec681f3Smrg      if (radv_layout_dcc_compressed(cmd_buffer->device, dst_img, dest_iview->base_mip,
7007ec681f3Smrg                                     dst_image_layout, false, queue_mask)) {
7017ec681f3Smrg         VkImageSubresourceRange range = {
7027ec681f3Smrg            .aspectMask = dest_iview->aspect_mask,
7037ec681f3Smrg            .baseMipLevel = dest_iview->base_mip,
7047ec681f3Smrg            .levelCount = dest_iview->level_count,
7057ec681f3Smrg            .baseArrayLayer = dest_iview->base_layer,
7067ec681f3Smrg            .layerCount = dest_iview->layer_count,
7077ec681f3Smrg         };
7087ec681f3Smrg
7097ec681f3Smrg         cmd_buffer->state.flush_bits |= radv_init_dcc(cmd_buffer, dst_img, &range, 0xffffffff);
7107ec681f3Smrg         cmd_buffer->state.attachments[dest_att.attachment].current_layout =
7117ec681f3Smrg            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
7127ec681f3Smrg      }
7137ec681f3Smrg
7147ec681f3Smrg      struct radv_subpass resolve_subpass = {
7157ec681f3Smrg         .color_count = 2,
7167ec681f3Smrg         .color_attachments = (struct radv_subpass_attachment[]){src_att, dest_att},
7177ec681f3Smrg         .depth_stencil_attachment = NULL,
7187ec681f3Smrg      };
7197ec681f3Smrg
7207ec681f3Smrg      radv_cmd_buffer_set_subpass(cmd_buffer, &resolve_subpass);
7217ec681f3Smrg
7227ec681f3Smrg      VkResult ret = build_resolve_pipeline(
7237ec681f3Smrg         cmd_buffer->device, radv_format_meta_fs_key(cmd_buffer->device, dest_iview->vk_format));
7247ec681f3Smrg      if (ret != VK_SUCCESS) {
7257ec681f3Smrg         cmd_buffer->record_result = ret;
7267ec681f3Smrg         continue;
7277ec681f3Smrg      }
7287ec681f3Smrg
7297ec681f3Smrg      emit_resolve(cmd_buffer, src_img, dst_img, dest_iview->vk_format, &(VkOffset2D){0, 0},
7307ec681f3Smrg                   &(VkExtent2D){fb->width, fb->height});
7317ec681f3Smrg   }
7327ec681f3Smrg
7337ec681f3Smrg   radv_cmd_buffer_restore_subpass(cmd_buffer, subpass);
7347ec681f3Smrg
7357ec681f3Smrg   radv_meta_restore(&saved_state, cmd_buffer);
73601e04c3fSmrg}
73701e04c3fSmrg
73801e04c3fSmrg/**
73901e04c3fSmrg * Emit any needed resolves for the current subpass.
74001e04c3fSmrg */
74101e04c3fSmrgvoid
74201e04c3fSmrgradv_cmd_buffer_resolve_subpass(struct radv_cmd_buffer *cmd_buffer)
74301e04c3fSmrg{
7447ec681f3Smrg   const struct radv_subpass *subpass = cmd_buffer->state.subpass;
7457ec681f3Smrg   enum radv_resolve_method resolve_method = RESOLVE_HW;
7467ec681f3Smrg
7477ec681f3Smrg   if (!subpass->has_color_resolve && !subpass->ds_resolve_attachment)
7487ec681f3Smrg      return;
7497ec681f3Smrg
7507ec681f3Smrg   radv_describe_begin_render_pass_resolve(cmd_buffer);
7517ec681f3Smrg
7527ec681f3Smrg   if (subpass->ds_resolve_attachment) {
7537ec681f3Smrg      struct radv_subpass_attachment src_att = *subpass->depth_stencil_attachment;
7547ec681f3Smrg      struct radv_subpass_attachment dst_att = *subpass->ds_resolve_attachment;
7557ec681f3Smrg      struct radv_image_view *src_iview = cmd_buffer->state.attachments[src_att.attachment].iview;
7567ec681f3Smrg      struct radv_image_view *dst_iview = cmd_buffer->state.attachments[dst_att.attachment].iview;
7577ec681f3Smrg
7587ec681f3Smrg      /* Make sure to not clear the depth/stencil attachment after resolves. */
7597ec681f3Smrg      cmd_buffer->state.attachments[dst_att.attachment].pending_clear_aspects = 0;
7607ec681f3Smrg
7617ec681f3Smrg      radv_pick_resolve_method_images(cmd_buffer->device, src_iview->image, src_iview->vk_format,
7627ec681f3Smrg                                      dst_iview->image, dst_iview->base_mip, dst_att.layout,
7637ec681f3Smrg                                      dst_att.in_render_loop, cmd_buffer, &resolve_method);
7647ec681f3Smrg
7657ec681f3Smrg      if ((src_iview->aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) &&
7667ec681f3Smrg          subpass->depth_resolve_mode != VK_RESOLVE_MODE_NONE_KHR) {
7677ec681f3Smrg         if (resolve_method == RESOLVE_FRAGMENT) {
7687ec681f3Smrg            radv_depth_stencil_resolve_subpass_fs(cmd_buffer, VK_IMAGE_ASPECT_DEPTH_BIT,
7697ec681f3Smrg                                                  subpass->depth_resolve_mode);
7707ec681f3Smrg         } else {
7717ec681f3Smrg            assert(resolve_method == RESOLVE_COMPUTE);
7727ec681f3Smrg            radv_depth_stencil_resolve_subpass_cs(cmd_buffer, VK_IMAGE_ASPECT_DEPTH_BIT,
7737ec681f3Smrg                                                  subpass->depth_resolve_mode);
7747ec681f3Smrg         }
7757ec681f3Smrg      }
7767ec681f3Smrg
7777ec681f3Smrg      if ((src_iview->aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) &&
7787ec681f3Smrg          subpass->stencil_resolve_mode != VK_RESOLVE_MODE_NONE_KHR) {
7797ec681f3Smrg         if (resolve_method == RESOLVE_FRAGMENT) {
7807ec681f3Smrg            radv_depth_stencil_resolve_subpass_fs(cmd_buffer, VK_IMAGE_ASPECT_STENCIL_BIT,
7817ec681f3Smrg                                                  subpass->stencil_resolve_mode);
7827ec681f3Smrg         } else {
7837ec681f3Smrg            assert(resolve_method == RESOLVE_COMPUTE);
7847ec681f3Smrg            radv_depth_stencil_resolve_subpass_cs(cmd_buffer, VK_IMAGE_ASPECT_STENCIL_BIT,
7857ec681f3Smrg                                                  subpass->stencil_resolve_mode);
7867ec681f3Smrg         }
7877ec681f3Smrg      }
7887ec681f3Smrg
7897ec681f3Smrg      /* From the Vulkan spec 1.2.165:
7907ec681f3Smrg       *
7917ec681f3Smrg       * "VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT specifies
7927ec681f3Smrg       *  write access to a color, resolve, or depth/stencil
7937ec681f3Smrg       *  resolve attachment during a render pass or via
7947ec681f3Smrg       *  certain subpass load and store operations."
7957ec681f3Smrg       *
7967ec681f3Smrg       * Yes, it's counterintuitive but it makes sense because ds
7977ec681f3Smrg       * resolve operations happen late at the end of the subpass.
7987ec681f3Smrg       *
7997ec681f3Smrg       * That said, RADV is wrong because it executes the subpass
8007ec681f3Smrg       * end barrier *before* any subpass resolves instead of after.
8017ec681f3Smrg       *
8027ec681f3Smrg       * TODO: Fix this properly by executing subpass end barriers
8037ec681f3Smrg       * after subpass resolves.
8047ec681f3Smrg       */
8057ec681f3Smrg      cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB;
8067ec681f3Smrg      if (radv_image_has_htile(dst_iview->image))
8077ec681f3Smrg         cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB_META;
8087ec681f3Smrg   }
8097ec681f3Smrg
8107ec681f3Smrg   if (subpass->has_color_resolve) {
8117ec681f3Smrg      for (uint32_t i = 0; i < subpass->color_count; ++i) {
8127ec681f3Smrg         struct radv_subpass_attachment src_att = subpass->color_attachments[i];
8137ec681f3Smrg         struct radv_subpass_attachment dest_att = subpass->resolve_attachments[i];
8147ec681f3Smrg
8157ec681f3Smrg         if (dest_att.attachment == VK_ATTACHMENT_UNUSED)
8167ec681f3Smrg            continue;
8177ec681f3Smrg
8187ec681f3Smrg         /* Make sure to not clear color attachments after resolves. */
8197ec681f3Smrg         cmd_buffer->state.attachments[dest_att.attachment].pending_clear_aspects = 0;
8207ec681f3Smrg
8217ec681f3Smrg         struct radv_image_view *dst_iview =
8227ec681f3Smrg            cmd_buffer->state.attachments[dest_att.attachment].iview;
8237ec681f3Smrg         struct radv_image *dst_img = dst_iview->image;
8247ec681f3Smrg         struct radv_image_view *src_iview =
8257ec681f3Smrg            cmd_buffer->state.attachments[src_att.attachment].iview;
8267ec681f3Smrg         struct radv_image *src_img = src_iview->image;
8277ec681f3Smrg
8287ec681f3Smrg         radv_pick_resolve_method_images(cmd_buffer->device, src_img, src_iview->vk_format, dst_img,
8297ec681f3Smrg                                         dst_iview->base_mip, dest_att.layout,
8307ec681f3Smrg                                         dest_att.in_render_loop, cmd_buffer, &resolve_method);
8317ec681f3Smrg
8327ec681f3Smrg         if (resolve_method == RESOLVE_FRAGMENT) {
8337ec681f3Smrg            break;
8347ec681f3Smrg         }
8357ec681f3Smrg      }
8367ec681f3Smrg
8377ec681f3Smrg      switch (resolve_method) {
8387ec681f3Smrg      case RESOLVE_HW:
8397ec681f3Smrg         radv_cmd_buffer_resolve_subpass_hw(cmd_buffer);
8407ec681f3Smrg         break;
8417ec681f3Smrg      case RESOLVE_COMPUTE:
8427ec681f3Smrg         radv_cmd_buffer_resolve_subpass_cs(cmd_buffer);
8437ec681f3Smrg         break;
8447ec681f3Smrg      case RESOLVE_FRAGMENT:
8457ec681f3Smrg         radv_cmd_buffer_resolve_subpass_fs(cmd_buffer);
8467ec681f3Smrg         break;
8477ec681f3Smrg      default:
8487ec681f3Smrg         unreachable("Invalid resolve method");
8497ec681f3Smrg      }
8507ec681f3Smrg   }
8517ec681f3Smrg
8527ec681f3Smrg   radv_describe_end_render_pass_resolve(cmd_buffer);
85301e04c3fSmrg}
85401e04c3fSmrg
85501e04c3fSmrg/**
85601e04c3fSmrg * Decompress CMask/FMask before resolving a multisampled source image inside a
85701e04c3fSmrg * subpass.
85801e04c3fSmrg */
85901e04c3fSmrgvoid
86001e04c3fSmrgradv_decompress_resolve_subpass_src(struct radv_cmd_buffer *cmd_buffer)
86101e04c3fSmrg{
8627ec681f3Smrg   const struct radv_subpass *subpass = cmd_buffer->state.subpass;
8637ec681f3Smrg   struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
8647ec681f3Smrg   uint32_t layer_count = fb->layers;
8657ec681f3Smrg
8667ec681f3Smrg   if (subpass->view_mask)
8677ec681f3Smrg      layer_count = util_last_bit(subpass->view_mask);
8687ec681f3Smrg
8697ec681f3Smrg   for (uint32_t i = 0; i < subpass->color_count; ++i) {
8707ec681f3Smrg      struct radv_subpass_attachment src_att = subpass->color_attachments[i];
8717ec681f3Smrg      struct radv_subpass_attachment dest_att = subpass->resolve_attachments[i];
8727ec681f3Smrg
8737ec681f3Smrg      if (dest_att.attachment == VK_ATTACHMENT_UNUSED)
8747ec681f3Smrg         continue;
87501e04c3fSmrg
8767ec681f3Smrg      struct radv_image_view *src_iview = cmd_buffer->state.attachments[src_att.attachment].iview;
8777ec681f3Smrg      struct radv_image *src_image = src_iview->image;
87801e04c3fSmrg
8797ec681f3Smrg      VkImageResolve2KHR region = {0};
8807ec681f3Smrg      region.sType = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR;
8817ec681f3Smrg      region.srcSubresource.aspectMask = src_iview->aspect_mask;
8827ec681f3Smrg      region.srcSubresource.mipLevel = 0;
8837ec681f3Smrg      region.srcSubresource.baseArrayLayer = src_iview->base_layer;
8847ec681f3Smrg      region.srcSubresource.layerCount = layer_count;
88501e04c3fSmrg
8867ec681f3Smrg      radv_decompress_resolve_src(cmd_buffer, src_image, src_att.layout, &region);
8877ec681f3Smrg   }
8887ec681f3Smrg}
8897ec681f3Smrg
8907ec681f3Smrgstatic struct radv_sample_locations_state *
8917ec681f3Smrgradv_get_resolve_sample_locations(struct radv_cmd_buffer *cmd_buffer)
8927ec681f3Smrg{
8937ec681f3Smrg   struct radv_cmd_state *state = &cmd_buffer->state;
8947ec681f3Smrg   uint32_t subpass_id = radv_get_subpass_id(cmd_buffer);
89501e04c3fSmrg
8967ec681f3Smrg   for (uint32_t i = 0; i < state->num_subpass_sample_locs; i++) {
8977ec681f3Smrg      if (state->subpass_sample_locs[i].subpass_idx == subpass_id)
8987ec681f3Smrg         return &state->subpass_sample_locs[i].sample_location;
8997ec681f3Smrg   }
90001e04c3fSmrg
9017ec681f3Smrg   return NULL;
90201e04c3fSmrg}
90301e04c3fSmrg
90401e04c3fSmrg/**
90501e04c3fSmrg * Decompress CMask/FMask before resolving a multisampled source image.
90601e04c3fSmrg */
90701e04c3fSmrgvoid
9087ec681f3Smrgradv_decompress_resolve_src(struct radv_cmd_buffer *cmd_buffer, struct radv_image *src_image,
9097ec681f3Smrg                            VkImageLayout src_image_layout, const VkImageResolve2KHR *region)
91001e04c3fSmrg{
9117ec681f3Smrg   const uint32_t src_base_layer =
9127ec681f3Smrg      radv_meta_get_iview_layer(src_image, &region->srcSubresource, &region->srcOffset);
9137ec681f3Smrg
9147ec681f3Smrg   VkImageMemoryBarrier barrier = {0};
9157ec681f3Smrg   barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
9167ec681f3Smrg   barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
9177ec681f3Smrg   barrier.oldLayout = src_image_layout;
9187ec681f3Smrg   barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
9197ec681f3Smrg   barrier.image = radv_image_to_handle(src_image);
9207ec681f3Smrg   barrier.subresourceRange = (VkImageSubresourceRange){
9217ec681f3Smrg      .aspectMask = region->srcSubresource.aspectMask,
9227ec681f3Smrg      .baseMipLevel = region->srcSubresource.mipLevel,
9237ec681f3Smrg      .levelCount = 1,
9247ec681f3Smrg      .baseArrayLayer = src_base_layer,
9257ec681f3Smrg      .layerCount = region->srcSubresource.layerCount,
9267ec681f3Smrg   };
9277ec681f3Smrg
9287ec681f3Smrg   if (src_image->flags & VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT) {
9297ec681f3Smrg      /* If the depth/stencil image uses different sample
9307ec681f3Smrg       * locations, we need them during HTILE decompressions.
9317ec681f3Smrg       */
9327ec681f3Smrg      struct radv_sample_locations_state *sample_locs =
9337ec681f3Smrg         radv_get_resolve_sample_locations(cmd_buffer);
9347ec681f3Smrg
9357ec681f3Smrg      barrier.pNext = &(VkSampleLocationsInfoEXT){
9367ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT,
9377ec681f3Smrg         .sampleLocationsPerPixel = sample_locs->per_pixel,
9387ec681f3Smrg         .sampleLocationGridSize = sample_locs->grid_size,
9397ec681f3Smrg         .sampleLocationsCount = sample_locs->count,
9407ec681f3Smrg         .pSampleLocations = sample_locs->locations,
9417ec681f3Smrg      };
9427ec681f3Smrg   }
9437ec681f3Smrg
9447ec681f3Smrg   radv_CmdPipelineBarrier(radv_cmd_buffer_to_handle(cmd_buffer), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
9457ec681f3Smrg                           VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, 0, NULL, 0, NULL, 1,
9467ec681f3Smrg                           &barrier);
94701e04c3fSmrg}
948