Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / amd / vulkan / radv_meta_blit2d.c
index f69fec8ea66bc359bd34a39f1b9bb768abfe9136..47939b2244306fc94af29ce05aacb35d2e7ca3b4 100644 (file)
 #include "nir/nir_builder.h"
 #include "vk_format.h"
 
-enum blit2d_dst_type {
-       /* We can bind this destination as a "normal" render target and render
-        * to it just like you would anywhere else.
-        */
-       BLIT2D_DST_TYPE_NORMAL,
-
-       /* The destination has a 3-channel RGB format.  Since we can't render to
-        * non-power-of-two textures, we have to bind it as a red texture and
-        * select the correct component for the given red pixel in the shader.
-        */
-       BLIT2D_DST_TYPE_RGB,
-
-       BLIT2D_NUM_DST_TYPES,
-};
-
-
 enum blit2d_src_type {
        BLIT2D_SRC_TYPE_IMAGE,
+       BLIT2D_SRC_TYPE_IMAGE_3D,
        BLIT2D_SRC_TYPE_BUFFER,
        BLIT2D_NUM_SRC_TYPES,
 };
 
+static VkResult
+blit2d_init_color_pipeline(struct radv_device *device,
+                          enum blit2d_src_type src_type,
+                          VkFormat format,
+                          uint32_t log2_samples);
+
+static VkResult
+blit2d_init_depth_only_pipeline(struct radv_device *device,
+                               enum blit2d_src_type src_type,
+                               uint32_t log2_samples);
+
+static VkResult
+blit2d_init_stencil_only_pipeline(struct radv_device *device,
+                                 enum blit2d_src_type src_type,
+                                 uint32_t log2_samples);
+
 static void
 create_iview(struct radv_cmd_buffer *cmd_buffer,
              struct radv_meta_blit2d_surf *surf,
-             VkImageUsageFlags usage,
-             struct radv_image_view *iview, VkFormat depth_format)
+             struct radv_image_view *iview, VkFormat depth_format,
+              VkImageAspectFlagBits aspects)
 {
        VkFormat format;
+       VkImageViewType view_type = cmd_buffer->device->physical_device->rad_info.chip_class < GFX9 ? VK_IMAGE_VIEW_TYPE_2D :
+               radv_meta_get_view_type(surf->image);
 
        if (depth_format)
                format = depth_format;
@@ -67,16 +70,16 @@ create_iview(struct radv_cmd_buffer *cmd_buffer,
                             &(VkImageViewCreateInfo) {
                                     .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
                                             .image = radv_image_to_handle(surf->image),
-                                            .viewType = VK_IMAGE_VIEW_TYPE_2D,
+                                            .viewType = view_type,
                                             .format = format,
                                             .subresourceRange = {
-                                            .aspectMask = surf->aspect_mask,
+                                            .aspectMask = aspects,
                                             .baseMipLevel = surf->level,
                                             .levelCount = 1,
                                             .baseArrayLayer = surf->layer,
                                             .layerCount = 1
                                     },
-                                            }, cmd_buffer, usage);
+                            }, NULL);
 }
 
 static void
@@ -98,7 +101,7 @@ create_bview(struct radv_cmd_buffer *cmd_buffer,
                                      .format = format,
                                      .offset = src->offset,
                                      .range = VK_WHOLE_SIZE,
-                             }, cmd_buffer);
+                             });
 
 }
 
@@ -112,7 +115,9 @@ blit2d_bind_src(struct radv_cmd_buffer *cmd_buffer,
                 struct radv_meta_blit2d_surf *src_img,
                 struct radv_meta_blit2d_buffer *src_buf,
                 struct blit2d_src_temps *tmp,
-                enum blit2d_src_type src_type, VkFormat depth_format)
+                enum blit2d_src_type src_type, VkFormat depth_format,
+                VkImageAspectFlagBits aspects,
+                uint32_t log2_samples)
 {
        struct radv_device *device = cmd_buffer->device;
 
@@ -120,7 +125,7 @@ blit2d_bind_src(struct radv_cmd_buffer *cmd_buffer,
                create_bview(cmd_buffer, src_buf, &tmp->bview, depth_format);
 
                radv_meta_push_descriptor_set(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                             device->meta_state.blit2d.p_layouts[src_type],
+                                             device->meta_state.blit2d[log2_samples].p_layouts[src_type],
                                              0, /* set */
                                              1, /* descriptorWriteCount */
                                              (VkWriteDescriptorSet[]) {
@@ -135,15 +140,20 @@ blit2d_bind_src(struct radv_cmd_buffer *cmd_buffer,
                                              });
 
                radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
-                                     device->meta_state.blit2d.p_layouts[src_type],
-                                     VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4,
+                                     device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+                                     VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4,
                                      &src_buf->pitch);
        } else {
-               create_iview(cmd_buffer, src_img, VK_IMAGE_USAGE_SAMPLED_BIT, &tmp->iview,
-                            depth_format);
+               create_iview(cmd_buffer, src_img, &tmp->iview, depth_format, aspects);
+
+               if (src_type == BLIT2D_SRC_TYPE_IMAGE_3D)
+                       radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
+                                             device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+                                             VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4,
+                                             &src_img->layer);
 
                radv_meta_push_descriptor_set(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                             device->meta_state.blit2d.p_layouts[src_type],
+                                             device->meta_state.blit2d[log2_samples].p_layouts[src_type],
                                              0, /* set */
                                              1, /* descriptorWriteCount */
                                              (VkWriteDescriptorSet[]) {
@@ -177,17 +187,10 @@ blit2d_bind_dst(struct radv_cmd_buffer *cmd_buffer,
                 uint32_t width,
                 uint32_t height,
                VkFormat depth_format,
-                struct blit2d_dst_temps *tmp)
+                struct blit2d_dst_temps *tmp,
+                VkImageAspectFlagBits aspects)
 {
-       VkImageUsageFlagBits bits;
-
-       if (dst->aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT)
-               bits = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
-       else
-               bits = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
-       create_iview(cmd_buffer, dst, bits,
-                    &tmp->iview, depth_format);
+       create_iview(cmd_buffer, dst, &tmp->iview, depth_format, aspects);
 
        radv_CreateFramebuffer(radv_device_to_handle(cmd_buffer->device),
                               &(VkFramebufferCreateInfo) {
@@ -202,51 +205,40 @@ blit2d_bind_dst(struct radv_cmd_buffer *cmd_buffer,
                                }, &cmd_buffer->pool->alloc, &tmp->fb);
 }
 
-static void
-blit2d_unbind_dst(struct radv_cmd_buffer *cmd_buffer,
-                  struct blit2d_dst_temps *tmp)
-{
-       VkDevice vk_device = radv_device_to_handle(cmd_buffer->device);
-       radv_DestroyFramebuffer(vk_device, tmp->fb, &cmd_buffer->pool->alloc);
-}
-
 static void
 bind_pipeline(struct radv_cmd_buffer *cmd_buffer,
-              enum blit2d_src_type src_type, unsigned fs_key)
+              enum blit2d_src_type src_type, unsigned fs_key,
+              uint32_t log2_samples)
 {
        VkPipeline pipeline =
-               cmd_buffer->device->meta_state.blit2d.pipelines[src_type][fs_key];
+               cmd_buffer->device->meta_state.blit2d[log2_samples].pipelines[src_type][fs_key];
 
-       if (cmd_buffer->state.pipeline != radv_pipeline_from_handle(pipeline)) {
-               radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
-                                    VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
-       }
+       radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
+                            VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 }
 
 static void
 bind_depth_pipeline(struct radv_cmd_buffer *cmd_buffer,
-                   enum blit2d_src_type src_type)
+                   enum blit2d_src_type src_type,
+                   uint32_t log2_samples)
 {
        VkPipeline pipeline =
-               cmd_buffer->device->meta_state.blit2d.depth_only_pipeline[src_type];
+               cmd_buffer->device->meta_state.blit2d[log2_samples].depth_only_pipeline[src_type];
 
-       if (cmd_buffer->state.pipeline != radv_pipeline_from_handle(pipeline)) {
-               radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
-                                    VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
-       }
+       radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
+                            VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 }
 
 static void
 bind_stencil_pipeline(struct radv_cmd_buffer *cmd_buffer,
-                     enum blit2d_src_type src_type)
+                     enum blit2d_src_type src_type,
+                     uint32_t log2_samples)
 {
        VkPipeline pipeline =
-               cmd_buffer->device->meta_state.blit2d.stencil_only_pipeline[src_type];
+               cmd_buffer->device->meta_state.blit2d[log2_samples].stencil_only_pipeline[src_type];
 
-       if (cmd_buffer->state.pipeline != radv_pipeline_from_handle(pipeline)) {
-               radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
-                                    VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
-       }
+       radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
+                            VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 }
 
 static void
@@ -255,159 +247,162 @@ radv_meta_blit2d_normal_dst(struct radv_cmd_buffer *cmd_buffer,
                            struct radv_meta_blit2d_buffer *src_buf,
                            struct radv_meta_blit2d_surf *dst,
                            unsigned num_rects,
-                           struct radv_meta_blit2d_rect *rects, enum blit2d_src_type src_type)
+                           struct radv_meta_blit2d_rect *rects, enum blit2d_src_type src_type,
+                           uint32_t log2_samples)
 {
        struct radv_device *device = cmd_buffer->device;
 
        for (unsigned r = 0; r < num_rects; ++r) {
-               VkFormat depth_format = 0;
-               if (dst->aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT)
-                       depth_format = vk_format_stencil_only(dst->image->vk_format);
-               else if (dst->aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT)
-                       depth_format = vk_format_depth_only(dst->image->vk_format);
-               struct blit2d_src_temps src_temps;
-               blit2d_bind_src(cmd_buffer, src_img, src_buf, &src_temps, src_type, depth_format);
-
-               uint32_t offset = 0;
-               struct blit2d_dst_temps dst_temps;
-               blit2d_bind_dst(cmd_buffer, dst, rects[r].dst_x + rects[r].width,
-                               rects[r].dst_y + rects[r].height, depth_format, &dst_temps);
-
-               struct blit_vb_data {
-                       float pos[2];
-                       float tex_coord[2];
-               } vb_data[3];
-
-               unsigned vb_size = 3 * sizeof(*vb_data);
-
-               vb_data[0] = (struct blit_vb_data) {
-                       .pos = {
-                               -1.0,
-                               -1.0,
-                       },
-                       .tex_coord = {
+               unsigned i;
+               for_each_bit(i, dst->aspect_mask) {
+                       unsigned aspect_mask = 1u << i;
+                       unsigned src_aspect_mask = aspect_mask;
+                       VkFormat depth_format = 0;
+                       if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT)
+                               depth_format = vk_format_stencil_only(dst->image->vk_format);
+                       else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT)
+                               depth_format = vk_format_depth_only(dst->image->vk_format);
+                       else if (src_img)
+                               src_aspect_mask = src_img->aspect_mask;
+
+                       struct blit2d_src_temps src_temps;
+                       blit2d_bind_src(cmd_buffer, src_img, src_buf, &src_temps, src_type, depth_format, src_aspect_mask, log2_samples);
+
+                       struct blit2d_dst_temps dst_temps;
+                       blit2d_bind_dst(cmd_buffer, dst, rects[r].dst_x + rects[r].width,
+                                       rects[r].dst_y + rects[r].height, depth_format, &dst_temps, aspect_mask);
+
+                       float vertex_push_constants[4] = {
                                rects[r].src_x,
                                rects[r].src_y,
-                       },
-               };
-
-               vb_data[1] = (struct blit_vb_data) {
-                       .pos = {
-                               -1.0,
-                               1.0,
-                       },
-                       .tex_coord = {
-                               rects[r].src_x,
-                               rects[r].src_y + rects[r].height,
-                       },
-               };
-
-               vb_data[2] = (struct blit_vb_data) {
-                       .pos = {
-                               1.0,
-                               -1.0,
-                       },
-                       .tex_coord = {
                                rects[r].src_x + rects[r].width,
-                               rects[r].src_y,
-                       },
-               };
-
-
-               radv_cmd_buffer_upload_data(cmd_buffer, vb_size, 16, vb_data, &offset);
-
-               struct radv_buffer vertex_buffer = {
-                       .device = device,
-                       .size = vb_size,
-                       .bo = cmd_buffer->upload.upload_bo,
-                       .offset = offset,
-               };
-
-               radv_CmdBindVertexBuffers(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1,
-                                         (VkBuffer[]) {
-                                                 radv_buffer_to_handle(&vertex_buffer),
-                                                         },
-                                         (VkDeviceSize[]) {
-                                                 0,
-                                                         });
-
-
-               if (dst->aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
-                       unsigned fs_key = radv_format_meta_fs_key(dst_temps.iview.vk_format);
-
-                       radv_CmdBeginRenderPass(radv_cmd_buffer_to_handle(cmd_buffer),
-                                                     &(VkRenderPassBeginInfo) {
-                                                             .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                                                                     .renderPass = device->meta_state.blit2d.render_passes[fs_key],
-                                                                     .framebuffer = dst_temps.fb,
-                                                                     .renderArea = {
-                                                                     .offset = { rects[r].dst_x, rects[r].dst_y, },
-                                                                     .extent = { rects[r].width, rects[r].height },
-                                                             },
-                                                                     .clearValueCount = 0,
-                                                                              .pClearValues = NULL,
-                                                                              }, VK_SUBPASS_CONTENTS_INLINE);
-
-
-                       bind_pipeline(cmd_buffer, src_type, fs_key);
-               } else if (dst->aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
-                       radv_CmdBeginRenderPass(radv_cmd_buffer_to_handle(cmd_buffer),
-                                                     &(VkRenderPassBeginInfo) {
-                                                             .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                                                                     .renderPass = device->meta_state.blit2d.depth_only_rp,
-                                                                     .framebuffer = dst_temps.fb,
-                                                                     .renderArea = {
-                                                                     .offset = { rects[r].dst_x, rects[r].dst_y, },
-                                                                     .extent = { rects[r].width, rects[r].height },
-                                                             },
-                                                                     .clearValueCount = 0,
-                                                                              .pClearValues = NULL,
-                                                                              }, VK_SUBPASS_CONTENTS_INLINE);
-
-
-                       bind_depth_pipeline(cmd_buffer, src_type);
-
-               } else if (dst->aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
-                       radv_CmdBeginRenderPass(radv_cmd_buffer_to_handle(cmd_buffer),
-                                                     &(VkRenderPassBeginInfo) {
-                                                             .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                                                                     .renderPass = device->meta_state.blit2d.stencil_only_rp,
-                                                                     .framebuffer = dst_temps.fb,
-                                                                     .renderArea = {
-                                                                     .offset = { rects[r].dst_x, rects[r].dst_y, },
-                                                                     .extent = { rects[r].width, rects[r].height },
-                                                             },
-                                                                     .clearValueCount = 0,
-                                                                              .pClearValues = NULL,
-                                                                              }, VK_SUBPASS_CONTENTS_INLINE);
-
-
-                       bind_stencil_pipeline(cmd_buffer, src_type);
+                               rects[r].src_y + rects[r].height,
+                       };
+
+                       radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
+                                       device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+                                       VK_SHADER_STAGE_VERTEX_BIT, 0, 16,
+                                       vertex_push_constants);
+
+                       if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT ||
+                           aspect_mask == VK_IMAGE_ASPECT_PLANE_0_BIT ||
+                           aspect_mask == VK_IMAGE_ASPECT_PLANE_1_BIT ||
+                           aspect_mask == VK_IMAGE_ASPECT_PLANE_2_BIT) {
+                               unsigned fs_key = radv_format_meta_fs_key(dst_temps.iview.vk_format);
+                               unsigned dst_layout = radv_meta_dst_layout_from_layout(dst->current_layout);
+
+                               if (device->meta_state.blit2d[log2_samples].pipelines[src_type][fs_key] == VK_NULL_HANDLE) {
+                                       VkResult ret = blit2d_init_color_pipeline(device, src_type, radv_fs_key_format_exemplars[fs_key], log2_samples);
+                                       if (ret != VK_SUCCESS) {
+                                               cmd_buffer->record_result = ret;
+                                               goto fail_pipeline;
+                                       }
+                               }
+
+                               radv_cmd_buffer_begin_render_pass(cmd_buffer,
+                                                                 &(VkRenderPassBeginInfo) {
+                                                                       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                                                       .renderPass = device->meta_state.blit2d_render_passes[fs_key][dst_layout],
+                                                                       .framebuffer = dst_temps.fb,
+                                                                       .renderArea = {
+                                                                               .offset = { rects[r].dst_x, rects[r].dst_y, },
+                                                                               .extent = { rects[r].width, rects[r].height },
+                                                                       },
+                                                                       .clearValueCount = 0,
+                                                                       .pClearValues = NULL,
+                                                                 });
+
+                               radv_cmd_buffer_set_subpass(cmd_buffer,
+                                                           &cmd_buffer->state.pass->subpasses[0]);
+
+                               bind_pipeline(cmd_buffer, src_type, fs_key, log2_samples);
+                       } else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
+                               enum radv_blit_ds_layout ds_layout = radv_meta_blit_ds_to_type(dst->current_layout);
+
+                               if (device->meta_state.blit2d[log2_samples].depth_only_pipeline[src_type] == VK_NULL_HANDLE) {
+                                       VkResult ret = blit2d_init_depth_only_pipeline(device, src_type, log2_samples);
+                                       if (ret != VK_SUCCESS) {
+                                               cmd_buffer->record_result = ret;
+                                               goto fail_pipeline;
+                                       }
+                               }
+
+                               radv_cmd_buffer_begin_render_pass(cmd_buffer,
+                                                                 &(VkRenderPassBeginInfo) {
+                                                                       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                                                       .renderPass = device->meta_state.blit2d_depth_only_rp[ds_layout],
+                                                                       .framebuffer = dst_temps.fb,
+                                                                       .renderArea = {
+                                                                               .offset = { rects[r].dst_x, rects[r].dst_y, },
+                                                                               .extent = { rects[r].width, rects[r].height },
+                                                                       },
+                                                                       .clearValueCount = 0,
+                                                                       .pClearValues = NULL,
+                                                                 });
+
+                               radv_cmd_buffer_set_subpass(cmd_buffer,
+                                                           &cmd_buffer->state.pass->subpasses[0]);
+
+                               bind_depth_pipeline(cmd_buffer, src_type, log2_samples);
+
+                       } else if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+                               enum radv_blit_ds_layout ds_layout = radv_meta_blit_ds_to_type(dst->current_layout);
+
+                               if (device->meta_state.blit2d[log2_samples].stencil_only_pipeline[src_type] == VK_NULL_HANDLE) {
+                                       VkResult ret = blit2d_init_stencil_only_pipeline(device, src_type, log2_samples);
+                                       if (ret != VK_SUCCESS) {
+                                               cmd_buffer->record_result = ret;
+                                               goto fail_pipeline;
+                                       }
+                               }
+
+                               radv_cmd_buffer_begin_render_pass(cmd_buffer,
+                                                                 &(VkRenderPassBeginInfo) {
+                                                                       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                                                       .renderPass = device->meta_state.blit2d_stencil_only_rp[ds_layout],
+                                                                       .framebuffer = dst_temps.fb,
+                                                                       .renderArea = {
+                                                                               .offset = { rects[r].dst_x, rects[r].dst_y, },
+                                                                               .extent = { rects[r].width, rects[r].height },
+                                                                       },
+                                                                       .clearValueCount = 0,
+                                                                       .pClearValues = NULL,
+                                                                  });
+
+                               radv_cmd_buffer_set_subpass(cmd_buffer,
+                                                           &cmd_buffer->state.pass->subpasses[0]);
+
+                               bind_stencil_pipeline(cmd_buffer, src_type, log2_samples);
+                       } else
+                               unreachable("Processing blit2d with multiple aspects.");
+
+                       radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
+                               .x = rects[r].dst_x,
+                               .y = rects[r].dst_y,
+                               .width = rects[r].width,
+                               .height = rects[r].height,
+                               .minDepth = 0.0f,
+                               .maxDepth = 1.0f
+                       });
+
+                       radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkRect2D) {
+                               .offset = (VkOffset2D) { rects[r].dst_x, rects[r].dst_y },
+                               .extent = (VkExtent2D) { rects[r].width, rects[r].height },
+                       });
+
+
+
+                       radv_CmdDraw(radv_cmd_buffer_to_handle(cmd_buffer), 3, 1, 0, 0);
+                       radv_cmd_buffer_end_render_pass(cmd_buffer);
+
+fail_pipeline:
+                       /* At the point where we emit the draw call, all data from the
+                       * descriptor sets, etc. has been used.  We are free to delete it.
+                       */
+                       radv_DestroyFramebuffer(radv_device_to_handle(device),
+                                               dst_temps.fb,
+                                               &cmd_buffer->pool->alloc);
                }
-
-               radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
-                       .x = rects[r].dst_x,
-                       .y = rects[r].dst_y,
-                       .width = rects[r].width,
-                       .height = rects[r].height,
-                       .minDepth = 0.0f,
-                       .maxDepth = 1.0f
-               });
-
-               radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkRect2D) {
-                       .offset = (VkOffset2D) { rects[r].dst_x, rects[r].dst_y },
-                       .extent = (VkExtent2D) { rects[r].width, rects[r].height },
-               });
-
-
-
-               radv_CmdDraw(radv_cmd_buffer_to_handle(cmd_buffer), 3, 1, 0, 0);
-               radv_CmdEndRenderPass(radv_cmd_buffer_to_handle(cmd_buffer));
-
-               /* At the point where we emit the draw call, all data from the
-                * descriptor sets, etc. has been used.  We are free to delete it.
-                */
-               blit2d_unbind_dst(cmd_buffer, &dst_temps);
        }
 }
 
@@ -419,10 +414,13 @@ radv_meta_blit2d(struct radv_cmd_buffer *cmd_buffer,
                 unsigned num_rects,
                 struct radv_meta_blit2d_rect *rects)
 {
+       bool use_3d = cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9 &&
+               (src_img && src_img->image->type == VK_IMAGE_TYPE_3D);
        enum blit2d_src_type src_type = src_buf ? BLIT2D_SRC_TYPE_BUFFER :
-                                                 BLIT2D_SRC_TYPE_IMAGE;
+               use_3d ? BLIT2D_SRC_TYPE_IMAGE_3D : BLIT2D_SRC_TYPE_IMAGE;
        radv_meta_blit2d_normal_dst(cmd_buffer, src_img, src_buf, dst,
-                                   num_rects, rects, src_type);
+                                   num_rects, rects, src_type,
+                                   src_img ? util_logbase2(src_img->image->info.samples) : 0);
 }
 
 static nir_shader *
@@ -433,55 +431,114 @@ build_nir_vertex_shader(void)
        nir_builder b;
 
        nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
-       b.shader->info->name = ralloc_strdup(b.shader, "meta_blit_vs");
+       b.shader->info.name = ralloc_strdup(b.shader, "meta_blit2d_vs");
 
-       nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
-                                                  vec4, "a_pos");
-       pos_in->data.location = VERT_ATTRIB_GENERIC0;
        nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
                                                    vec4, "gl_Position");
        pos_out->data.location = VARYING_SLOT_POS;
-       nir_copy_var(&b, pos_out, pos_in);
 
-       nir_variable *tex_pos_in = nir_variable_create(b.shader, nir_var_shader_in,
-                                                      vec2, "a_tex_pos");
-       tex_pos_in->data.location = VERT_ATTRIB_GENERIC1;
        nir_variable *tex_pos_out = nir_variable_create(b.shader, nir_var_shader_out,
                                                        vec2, "v_tex_pos");
        tex_pos_out->data.location = VARYING_SLOT_VAR0;
        tex_pos_out->data.interpolation = INTERP_MODE_SMOOTH;
-       nir_copy_var(&b, tex_pos_out, tex_pos_in);
 
+       nir_ssa_def *outvec = radv_meta_gen_rect_vertices(&b);
+       nir_store_var(&b, pos_out, outvec, 0xf);
+
+       nir_intrinsic_instr *src_box = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
+       src_box->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
+       nir_intrinsic_set_base(src_box, 0);
+       nir_intrinsic_set_range(src_box, 16);
+       src_box->num_components = 4;
+       nir_ssa_dest_init(&src_box->instr, &src_box->dest, 4, 32, "src_box");
+       nir_builder_instr_insert(&b, &src_box->instr);
+
+       nir_intrinsic_instr *vertex_id = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_vertex_id_zero_base);
+       nir_ssa_dest_init(&vertex_id->instr, &vertex_id->dest, 1, 32, "vertexid");
+       nir_builder_instr_insert(&b, &vertex_id->instr);
+
+       /* vertex 0 - src_x, src_y */
+       /* vertex 1 - src_x, src_y+h */
+       /* vertex 2 - src_x+w, src_y */
+       /* so channel 0 is vertex_id != 2 ? src_x : src_x + w
+          channel 1 is vertex id != 1 ? src_y : src_y + w */
+
+       nir_ssa_def *c0cmp = nir_ine(&b, &vertex_id->dest.ssa,
+                                    nir_imm_int(&b, 2));
+       nir_ssa_def *c1cmp = nir_ine(&b, &vertex_id->dest.ssa,
+                                    nir_imm_int(&b, 1));
+
+       nir_ssa_def *comp[2];
+       comp[0] = nir_bcsel(&b, c0cmp,
+                           nir_channel(&b, &src_box->dest.ssa, 0),
+                           nir_channel(&b, &src_box->dest.ssa, 2));
+
+       comp[1] = nir_bcsel(&b, c1cmp,
+                           nir_channel(&b, &src_box->dest.ssa, 1),
+                           nir_channel(&b, &src_box->dest.ssa, 3));
+       nir_ssa_def *out_tex_vec = nir_vec(&b, comp, 2);
+       nir_store_var(&b, tex_pos_out, out_tex_vec, 0x3);
        return b.shader;
 }
 
 typedef nir_ssa_def* (*texel_fetch_build_func)(struct nir_builder *,
                                                struct radv_device *,
-                                               nir_ssa_def *);
+                                               nir_ssa_def *, bool, bool);
 
 static nir_ssa_def *
 build_nir_texel_fetch(struct nir_builder *b, struct radv_device *device,
-                      nir_ssa_def *tex_pos)
+                      nir_ssa_def *tex_pos, bool is_3d, bool is_multisampled)
 {
+       enum glsl_sampler_dim dim =
+               is_3d ? GLSL_SAMPLER_DIM_3D : is_multisampled ? GLSL_SAMPLER_DIM_MS : GLSL_SAMPLER_DIM_2D;
        const struct glsl_type *sampler_type =
-               glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_UINT);
+               glsl_sampler_type(dim, false, false, GLSL_TYPE_UINT);
        nir_variable *sampler = nir_variable_create(b->shader, nir_var_uniform,
                                                    sampler_type, "s_tex");
        sampler->data.descriptor_set = 0;
        sampler->data.binding = 0;
 
-       nir_tex_instr *tex = nir_tex_instr_create(b->shader, 2);
-       tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
-       tex->op = nir_texop_txf;
+       nir_ssa_def *tex_pos_3d = NULL;
+       nir_intrinsic_instr *sample_idx = NULL;
+       if (is_3d) {
+               nir_intrinsic_instr *layer = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_push_constant);
+               nir_intrinsic_set_base(layer, 16);
+               nir_intrinsic_set_range(layer, 4);
+               layer->src[0] = nir_src_for_ssa(nir_imm_int(b, 0));
+               layer->num_components = 1;
+               nir_ssa_dest_init(&layer->instr, &layer->dest, 1, 32, "layer");
+               nir_builder_instr_insert(b, &layer->instr);
+
+               nir_ssa_def *chans[3];
+               chans[0] = nir_channel(b, tex_pos, 0);
+               chans[1] = nir_channel(b, tex_pos, 1);
+               chans[2] = &layer->dest.ssa;
+               tex_pos_3d = nir_vec(b, chans, 3);
+       }
+       if (is_multisampled) {
+               sample_idx = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_sample_id);
+               nir_ssa_dest_init(&sample_idx->instr, &sample_idx->dest, 1, 32, "sample_idx");
+               nir_builder_instr_insert(b, &sample_idx->instr);
+       }
+
+       nir_ssa_def *tex_deref = &nir_build_deref_var(b, sampler)->dest.ssa;
+
+       nir_tex_instr *tex = nir_tex_instr_create(b->shader, is_multisampled ? 4 : 3);
+       tex->sampler_dim = dim;
+       tex->op = is_multisampled ? nir_texop_txf_ms : nir_texop_txf;
        tex->src[0].src_type = nir_tex_src_coord;
-       tex->src[0].src = nir_src_for_ssa(tex_pos);
-       tex->src[1].src_type = nir_tex_src_lod;
-       tex->src[1].src = nir_src_for_ssa(nir_imm_int(b, 0));
+       tex->src[0].src = nir_src_for_ssa(is_3d ? tex_pos_3d : tex_pos);
+       tex->src[1].src_type = is_multisampled ? nir_tex_src_ms_index : nir_tex_src_lod;
+       tex->src[1].src = nir_src_for_ssa(is_multisampled ? &sample_idx->dest.ssa : nir_imm_int(b, 0));
+       tex->src[2].src_type = nir_tex_src_texture_deref;
+       tex->src[2].src = nir_src_for_ssa(tex_deref);
+       if (is_multisampled) {
+               tex->src[3].src_type = nir_tex_src_lod;
+               tex->src[3].src = nir_src_for_ssa(nir_imm_int(b, 0));
+       }
        tex->dest_type = nir_type_uint;
        tex->is_array = false;
-       tex->coord_components = 2;
-       tex->texture = nir_deref_var_create(tex, sampler);
-       tex->sampler = NULL;
+       tex->coord_components = is_3d ? 3 : 2;
 
        nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
        nir_builder_instr_insert(b, &tex->instr);
@@ -492,7 +549,7 @@ build_nir_texel_fetch(struct nir_builder *b, struct radv_device *device,
 
 static nir_ssa_def *
 build_nir_buffer_fetch(struct nir_builder *b, struct radv_device *device,
-                      nir_ssa_def *tex_pos)
+                      nir_ssa_def *tex_pos, bool is_3d, bool is_multisampled)
 {
        const struct glsl_type *sampler_type =
                glsl_sampler_type(GLSL_SAMPLER_DIM_BUF, false, false, GLSL_TYPE_UINT);
@@ -502,6 +559,8 @@ build_nir_buffer_fetch(struct nir_builder *b, struct radv_device *device,
        sampler->data.binding = 0;
 
        nir_intrinsic_instr *width = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_push_constant);
+       nir_intrinsic_set_base(width, 16);
+       nir_intrinsic_set_range(width, 4);
        width->src[0] = nir_src_for_ssa(nir_imm_int(b, 0));
        width->num_components = 1;
        nir_ssa_dest_init(&width->instr, &width->dest, 1, 32, "width");
@@ -511,18 +570,19 @@ build_nir_buffer_fetch(struct nir_builder *b, struct radv_device *device,
        nir_ssa_def *pos_y = nir_channel(b, tex_pos, 1);
        pos_y = nir_imul(b, pos_y, &width->dest.ssa);
        pos_x = nir_iadd(b, pos_x, pos_y);
-       //pos_x = nir_iadd(b, pos_x, nir_imm_int(b, 100000));
 
-       nir_tex_instr *tex = nir_tex_instr_create(b->shader, 1);
+       nir_ssa_def *tex_deref = &nir_build_deref_var(b, sampler)->dest.ssa;
+
+       nir_tex_instr *tex = nir_tex_instr_create(b->shader, 2);
        tex->sampler_dim = GLSL_SAMPLER_DIM_BUF;
        tex->op = nir_texop_txf;
        tex->src[0].src_type = nir_tex_src_coord;
        tex->src[0].src = nir_src_for_ssa(pos_x);
+       tex->src[1].src_type = nir_tex_src_texture_deref;
+       tex->src[1].src = nir_src_for_ssa(tex_deref);
        tex->dest_type = nir_type_uint;
        tex->is_array = false;
        tex->coord_components = 1;
-       tex->texture = nir_deref_var_create(tex, sampler);
-       tex->sampler = NULL;
 
        nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
        nir_builder_instr_insert(b, &tex->instr);
@@ -532,43 +592,21 @@ build_nir_buffer_fetch(struct nir_builder *b, struct radv_device *device,
 
 static const VkPipelineVertexInputStateCreateInfo normal_vi_create_info = {
        .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-       .vertexBindingDescriptionCount = 1,
-       .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
-               {
-                       .binding = 0,
-                       .stride = 4 * sizeof(float),
-                       .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
-               },
-       },
-       .vertexAttributeDescriptionCount = 2,
-       .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
-               {
-                       /* Position */
-                       .location = 0,
-                       .binding = 0,
-                       .format = VK_FORMAT_R32G32_SFLOAT,
-                       .offset = 0
-               },
-               {
-                       /* Texture Coordinate */
-                       .location = 1,
-                       .binding = 0,
-                       .format = VK_FORMAT_R32G32_SFLOAT,
-                       .offset = 8
-               },
-       },
+       .vertexBindingDescriptionCount = 0,
+       .vertexAttributeDescriptionCount = 0,
 };
 
 static nir_shader *
 build_nir_copy_fragment_shader(struct radv_device *device,
-                               texel_fetch_build_func txf_func, const char* name)
+                               texel_fetch_build_func txf_func, const char* name, bool is_3d,
+                               bool is_multisampled)
 {
        const struct glsl_type *vec4 = glsl_vec4_type();
        const struct glsl_type *vec2 = glsl_vector_type(GLSL_TYPE_FLOAT, 2);
        nir_builder b;
 
        nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
-       b.shader->info->name = ralloc_strdup(b.shader, name);
+       b.shader->info.name = ralloc_strdup(b.shader, name);
 
        nir_variable *tex_pos_in = nir_variable_create(b.shader, nir_var_shader_in,
                                                       vec2, "v_tex_pos");
@@ -579,10 +617,9 @@ build_nir_copy_fragment_shader(struct radv_device *device,
        color_out->data.location = FRAG_RESULT_DATA0;
 
        nir_ssa_def *pos_int = nir_f2i32(&b, nir_load_var(&b, tex_pos_in));
-       unsigned swiz[4] = { 0, 1 };
-       nir_ssa_def *tex_pos = nir_swizzle(&b, pos_int, swiz, 2, false);
+       nir_ssa_def *tex_pos = nir_channels(&b, pos_int, 0x3);
 
-       nir_ssa_def *color = txf_func(&b, device, tex_pos);
+       nir_ssa_def *color = txf_func(&b, device, tex_pos, is_3d, is_multisampled);
        nir_store_var(&b, color_out, color, 0xf);
 
        return b.shader;
@@ -590,14 +627,15 @@ build_nir_copy_fragment_shader(struct radv_device *device,
 
 static nir_shader *
 build_nir_copy_fragment_shader_depth(struct radv_device *device,
-                                    texel_fetch_build_func txf_func, const char* name)
+                                    texel_fetch_build_func txf_func, const char* name, bool is_3d,
+                                    bool is_multisampled)
 {
        const struct glsl_type *vec4 = glsl_vec4_type();
        const struct glsl_type *vec2 = glsl_vector_type(GLSL_TYPE_FLOAT, 2);
        nir_builder b;
 
        nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
-       b.shader->info->name = ralloc_strdup(b.shader, name);
+       b.shader->info.name = ralloc_strdup(b.shader, name);
 
        nir_variable *tex_pos_in = nir_variable_create(b.shader, nir_var_shader_in,
                                                       vec2, "v_tex_pos");
@@ -608,10 +646,9 @@ build_nir_copy_fragment_shader_depth(struct radv_device *device,
        color_out->data.location = FRAG_RESULT_DEPTH;
 
        nir_ssa_def *pos_int = nir_f2i32(&b, nir_load_var(&b, tex_pos_in));
-       unsigned swiz[4] = { 0, 1 };
-       nir_ssa_def *tex_pos = nir_swizzle(&b, pos_int, swiz, 2, false);
+       nir_ssa_def *tex_pos = nir_channels(&b, pos_int, 0x3);
 
-       nir_ssa_def *color = txf_func(&b, device, tex_pos);
+       nir_ssa_def *color = txf_func(&b, device, tex_pos, is_3d, is_multisampled);
        nir_store_var(&b, color_out, color, 0x1);
 
        return b.shader;
@@ -619,14 +656,15 @@ build_nir_copy_fragment_shader_depth(struct radv_device *device,
 
 static nir_shader *
 build_nir_copy_fragment_shader_stencil(struct radv_device *device,
-                                      texel_fetch_build_func txf_func, const char* name)
+                                      texel_fetch_build_func txf_func, const char* name, bool is_3d,
+                                      bool is_multisampled)
 {
        const struct glsl_type *vec4 = glsl_vec4_type();
        const struct glsl_type *vec2 = glsl_vector_type(GLSL_TYPE_FLOAT, 2);
        nir_builder b;
 
        nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
-       b.shader->info->name = ralloc_strdup(b.shader, name);
+       b.shader->info.name = ralloc_strdup(b.shader, name);
 
        nir_variable *tex_pos_in = nir_variable_create(b.shader, nir_var_shader_in,
                                                       vec2, "v_tex_pos");
@@ -637,10 +675,9 @@ build_nir_copy_fragment_shader_stencil(struct radv_device *device,
        color_out->data.location = FRAG_RESULT_STENCIL;
 
        nir_ssa_def *pos_int = nir_f2i32(&b, nir_load_var(&b, tex_pos_in));
-       unsigned swiz[4] = { 0, 1 };
-       nir_ssa_def *tex_pos = nir_swizzle(&b, pos_int, swiz, 2, false);
+       nir_ssa_def *tex_pos = nir_channels(&b, pos_int, 0x3);
 
-       nir_ssa_def *color = txf_func(&b, device, tex_pos);
+       nir_ssa_def *color = txf_func(&b, device, tex_pos, is_3d, is_multisampled);
        nir_store_var(&b, color_out, color, 0x1);
 
        return b.shader;
@@ -649,66 +686,74 @@ build_nir_copy_fragment_shader_stencil(struct radv_device *device,
 void
 radv_device_finish_meta_blit2d_state(struct radv_device *device)
 {
+       struct radv_meta_state *state = &device->meta_state;
+
        for(unsigned j = 0; j < NUM_META_FS_KEYS; ++j) {
-               if (device->meta_state.blit2d.render_passes[j]) {
+               for (unsigned k = 0; k < RADV_META_DST_LAYOUT_COUNT; ++k) {
                        radv_DestroyRenderPass(radv_device_to_handle(device),
-                                              device->meta_state.blit2d.render_passes[j],
-                                              &device->meta_state.alloc);
+                                              state->blit2d_render_passes[j][k],
+                                              &state->alloc);
                }
        }
 
-       radv_DestroyRenderPass(radv_device_to_handle(device),
-                              device->meta_state.blit2d.depth_only_rp,
-                              &device->meta_state.alloc);
-       radv_DestroyRenderPass(radv_device_to_handle(device),
-                              device->meta_state.blit2d.stencil_only_rp,
-                              &device->meta_state.alloc);
+       for (enum radv_blit_ds_layout j = RADV_BLIT_DS_LAYOUT_TILE_ENABLE; j < RADV_BLIT_DS_LAYOUT_COUNT; j++) {
+               radv_DestroyRenderPass(radv_device_to_handle(device),
+                                      state->blit2d_depth_only_rp[j], &state->alloc);
+               radv_DestroyRenderPass(radv_device_to_handle(device),
+                                      state->blit2d_stencil_only_rp[j], &state->alloc);
+       }
 
-       for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
-               if (device->meta_state.blit2d.p_layouts[src]) {
+       for (unsigned log2_samples = 0; log2_samples < MAX_SAMPLES_LOG2; ++log2_samples) {
+               for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
                        radv_DestroyPipelineLayout(radv_device_to_handle(device),
-                                               device->meta_state.blit2d.p_layouts[src],
-                                               &device->meta_state.alloc);
-               }
-
-               if (device->meta_state.blit2d.ds_layouts[src]) {
+                                                  state->blit2d[log2_samples].p_layouts[src],
+                                                  &state->alloc);
                        radv_DestroyDescriptorSetLayout(radv_device_to_handle(device),
-                                                       device->meta_state.blit2d.ds_layouts[src],
-                                                       &device->meta_state.alloc);
-               }
+                                                       state->blit2d[log2_samples].ds_layouts[src],
+                                                       &state->alloc);
 
-               for (unsigned j = 0; j < NUM_META_FS_KEYS; ++j) {
-                       if (device->meta_state.blit2d.pipelines[src][j]) {
+                       for (unsigned j = 0; j < NUM_META_FS_KEYS; ++j) {
                                radv_DestroyPipeline(radv_device_to_handle(device),
-                                                    device->meta_state.blit2d.pipelines[src][j],
-                                                    &device->meta_state.alloc);
+                                                    state->blit2d[log2_samples].pipelines[src][j],
+                                                    &state->alloc);
                        }
-               }
 
-               radv_DestroyPipeline(radv_device_to_handle(device),
-                                    device->meta_state.blit2d.depth_only_pipeline[src],
-                                    &device->meta_state.alloc);
-               radv_DestroyPipeline(radv_device_to_handle(device),
-                                    device->meta_state.blit2d.stencil_only_pipeline[src],
-                                    &device->meta_state.alloc);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->blit2d[log2_samples].depth_only_pipeline[src],
+                                            &state->alloc);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->blit2d[log2_samples].stencil_only_pipeline[src],
+                                            &state->alloc);
+               }
        }
 }
 
 static VkResult
 blit2d_init_color_pipeline(struct radv_device *device,
                           enum blit2d_src_type src_type,
-                          VkFormat format)
+                          VkFormat format,
+                          uint32_t log2_samples)
 {
        VkResult result;
        unsigned fs_key = radv_format_meta_fs_key(format);
        const char *name;
 
+       mtx_lock(&device->meta_state.mtx);
+       if (device->meta_state.blit2d[log2_samples].pipelines[src_type][fs_key]) {
+               mtx_unlock(&device->meta_state.mtx);
+               return VK_SUCCESS;
+       }
+
        texel_fetch_build_func src_func;
        switch(src_type) {
        case BLIT2D_SRC_TYPE_IMAGE:
                src_func = build_nir_texel_fetch;
                name = "meta_blit2d_image_fs";
                break;
+       case BLIT2D_SRC_TYPE_IMAGE_3D:
+               src_func = build_nir_texel_fetch;
+               name = "meta_blit3d_image_fs";
+               break;
        case BLIT2D_SRC_TYPE_BUFFER:
                src_func = build_nir_buffer_fetch;
                name = "meta_blit2d_buffer_fs";
@@ -722,7 +767,7 @@ blit2d_init_color_pipeline(struct radv_device *device,
        struct radv_shader_module fs = { .nir = NULL };
 
 
-       fs.nir = build_nir_copy_fragment_shader(device, src_func, name);
+       fs.nir = build_nir_copy_fragment_shader(device, src_func, name, src_type == BLIT2D_SRC_TYPE_IMAGE_3D, log2_samples > 0);
        vi_create_info = &normal_vi_create_info;
 
        struct radv_shader_module vs = {
@@ -745,37 +790,61 @@ blit2d_init_color_pipeline(struct radv_device *device,
                },
        };
 
-       if (!device->meta_state.blit2d.render_passes[fs_key]) {
-               result = radv_CreateRenderPass(radv_device_to_handle(device),
-                                              &(VkRenderPassCreateInfo) {
-                                                      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-                                                      .attachmentCount = 1,
-                                                      .pAttachments = &(VkAttachmentDescription) {
-                                                      .format = format,
-                                                      .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
-                                                      .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                                      .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      },
-                                              .subpassCount = 1,
-                                              .pSubpasses = &(VkSubpassDescription) {
-                                                      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                      .inputAttachmentCount = 0,
-                                                      .colorAttachmentCount = 1,
-                                                      .pColorAttachments = &(VkAttachmentReference) {
-                                                              .attachment = 0,
-                                                              .layout = VK_IMAGE_LAYOUT_GENERAL,
+       for (unsigned dst_layout = 0; dst_layout < RADV_META_DST_LAYOUT_COUNT; ++dst_layout) {
+               if (!device->meta_state.blit2d_render_passes[fs_key][dst_layout]) {
+                       VkImageLayout layout = radv_meta_dst_layout_to_layout(dst_layout);
+
+                       result = radv_CreateRenderPass(radv_device_to_handle(device),
+                                               &(VkRenderPassCreateInfo) {
+                                                       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+                                                       .attachmentCount = 1,
+                                                       .pAttachments = &(VkAttachmentDescription) {
+                                                       .format = format,
+                                                       .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
+                                                       .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                                       .initialLayout = layout,
+                                                       .finalLayout = layout,
+                                                       },
+                                               .subpassCount = 1,
+                                               .pSubpasses = &(VkSubpassDescription) {
+                                                       .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                                       .inputAttachmentCount = 0,
+                                                       .colorAttachmentCount = 1,
+                                                       .pColorAttachments = &(VkAttachmentReference) {
+                                                               .attachment = 0,
+                                                               .layout = layout,
+                                                               },
+                                               .pResolveAttachments = NULL,
+                                               .pDepthStencilAttachment = &(VkAttachmentReference) {
+                                                       .attachment = VK_ATTACHMENT_UNUSED,
+                                                       .layout = layout,
+                                               },
+                                               .preserveAttachmentCount = 0,
+                                               .pPreserveAttachments = NULL,
+                                               },
+                                               .dependencyCount = 2,
+                                               .pDependencies = (VkSubpassDependency[]) {
+                                                       {
+                                                               .srcSubpass = VK_SUBPASS_EXTERNAL,
+                                                               .dstSubpass = 0,
+                                                               .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                               .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                               .srcAccessMask = 0,
+                                                               .dstAccessMask = 0,
+                                                               .dependencyFlags = 0
                                                        },
-                                              .pResolveAttachments = NULL,
-                                              .pDepthStencilAttachment = &(VkAttachmentReference) {
-                                                      .attachment = VK_ATTACHMENT_UNUSED,
-                                                      .layout = VK_IMAGE_LAYOUT_GENERAL,
-                                              },
-                                              .preserveAttachmentCount = 1,
-                                              .pPreserveAttachments = (uint32_t[]) { 0 },
-                                              },
-                                       .dependencyCount = 0,
-                                }, &device->meta_state.alloc, &device->meta_state.blit2d.render_passes[fs_key]);
+                                                       {
+                                                               .srcSubpass = 0,
+                                                               .dstSubpass = VK_SUBPASS_EXTERNAL,
+                                                               .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                               .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                               .srcAccessMask = 0,
+                                                               .dstAccessMask = 0,
+                                                               .dependencyFlags = 0
+                                                       }
+                                               },
+                                       }, &device->meta_state.alloc, &device->meta_state.blit2d_render_passes[fs_key][dst_layout]);
+               }
        }
 
        const VkGraphicsPipelineCreateInfo vk_pipeline_info = {
@@ -802,8 +871,9 @@ blit2d_init_color_pipeline(struct radv_device *device,
                },
                .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
                        .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-                       .rasterizationSamples = 1,
-                       .sampleShadingEnable = false,
+                       .rasterizationSamples = 1 << log2_samples,
+                       .sampleShadingEnable = log2_samples > 1,
+                       .minSampleShading = 1.0,
                        .pSampleMask = (VkSampleMask[]) { UINT32_MAX },
                },
                .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
@@ -833,8 +903,8 @@ blit2d_init_color_pipeline(struct radv_device *device,
                        },
                },
                .flags = 0,
-               .layout = device->meta_state.blit2d.p_layouts[src_type],
-               .renderPass = device->meta_state.blit2d.render_passes[fs_key],
+               .layout = device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+               .renderPass = device->meta_state.blit2d_render_passes[fs_key][0],
                .subpass = 0,
        };
 
@@ -846,28 +916,40 @@ blit2d_init_color_pipeline(struct radv_device *device,
                                               radv_pipeline_cache_to_handle(&device->meta_state.cache),
                                               &vk_pipeline_info, &radv_pipeline_info,
                                               &device->meta_state.alloc,
-                                              &device->meta_state.blit2d.pipelines[src_type][fs_key]);
+                                              &device->meta_state.blit2d[log2_samples].pipelines[src_type][fs_key]);
 
 
        ralloc_free(vs.nir);
        ralloc_free(fs.nir);
 
+       mtx_unlock(&device->meta_state.mtx);
        return result;
 }
 
 static VkResult
 blit2d_init_depth_only_pipeline(struct radv_device *device,
-                               enum blit2d_src_type src_type)
+                               enum blit2d_src_type src_type,
+                               uint32_t log2_samples)
 {
        VkResult result;
        const char *name;
 
+       mtx_lock(&device->meta_state.mtx);
+       if (device->meta_state.blit2d[log2_samples].depth_only_pipeline[src_type]) {
+               mtx_unlock(&device->meta_state.mtx);
+               return VK_SUCCESS;
+       }
+
        texel_fetch_build_func src_func;
        switch(src_type) {
        case BLIT2D_SRC_TYPE_IMAGE:
                src_func = build_nir_texel_fetch;
                name = "meta_blit2d_depth_image_fs";
                break;
+       case BLIT2D_SRC_TYPE_IMAGE_3D:
+               src_func = build_nir_texel_fetch;
+               name = "meta_blit3d_depth_image_fs";
+               break;
        case BLIT2D_SRC_TYPE_BUFFER:
                src_func = build_nir_buffer_fetch;
                name = "meta_blit2d_depth_buffer_fs";
@@ -880,7 +962,7 @@ blit2d_init_depth_only_pipeline(struct radv_device *device,
        const VkPipelineVertexInputStateCreateInfo *vi_create_info;
        struct radv_shader_module fs = { .nir = NULL };
 
-       fs.nir = build_nir_copy_fragment_shader_depth(device, src_func, name);
+       fs.nir = build_nir_copy_fragment_shader_depth(device, src_func, name, src_type == BLIT2D_SRC_TYPE_IMAGE_3D, log2_samples > 0);
        vi_create_info = &normal_vi_create_info;
 
        struct radv_shader_module vs = {
@@ -903,34 +985,57 @@ blit2d_init_depth_only_pipeline(struct radv_device *device,
                },
        };
 
-       if (!device->meta_state.blit2d.depth_only_rp) {
-               result = radv_CreateRenderPass(radv_device_to_handle(device),
-                                              &(VkRenderPassCreateInfo) {
-                                                      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+       for (enum radv_blit_ds_layout ds_layout = RADV_BLIT_DS_LAYOUT_TILE_ENABLE; ds_layout < RADV_BLIT_DS_LAYOUT_COUNT; ds_layout++) {
+               if (!device->meta_state.blit2d_depth_only_rp[ds_layout]) {
+                       VkImageLayout layout = radv_meta_blit_ds_to_layout(ds_layout);
+                       result = radv_CreateRenderPass(radv_device_to_handle(device),
+                                                      &(VkRenderPassCreateInfo) {
+                                                              .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
                                                               .attachmentCount = 1,
                                                               .pAttachments = &(VkAttachmentDescription) {
-                                                              .format = 0,
-                                                              .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
-                                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                                              .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                              .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      },
-                                                      .subpassCount = 1,
-                                                      .pSubpasses = &(VkSubpassDescription) {
-                                                      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                      .inputAttachmentCount = 0,
-                                                      .colorAttachmentCount = 0,
-                                                      .pColorAttachments = NULL,
-                                                      .pResolveAttachments = NULL,
-                                                      .pDepthStencilAttachment = &(VkAttachmentReference) {
-                                                              .attachment = 0,
-                                                              .layout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      },
-                                                      .preserveAttachmentCount = 1,
-                                                      .pPreserveAttachments = (uint32_t[]) { 0 },
-                                              },
-                                                               .dependencyCount = 0,
-                                                }, &device->meta_state.alloc, &device->meta_state.blit2d.depth_only_rp);
+                                                                      .format = VK_FORMAT_D32_SFLOAT,
+                                                                      .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
+                                                                      .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                                                      .initialLayout = layout,
+                                                                      .finalLayout = layout,
+                                                              },
+                                                              .subpassCount = 1,
+                                                              .pSubpasses = &(VkSubpassDescription) {
+                                                                      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                                                      .inputAttachmentCount = 0,
+                                                                      .colorAttachmentCount = 0,
+                                                                      .pColorAttachments = NULL,
+                                                                      .pResolveAttachments = NULL,
+                                                                      .pDepthStencilAttachment = &(VkAttachmentReference) {
+                                                                              .attachment = 0,
+                                                                              .layout = layout,
+                                                                      },
+                                                                      .preserveAttachmentCount = 0,
+                                                                      .pPreserveAttachments = NULL,
+                                                              },
+                                                              .dependencyCount = 2,
+                                                              .pDependencies = (VkSubpassDependency[]) {
+                                                               {
+                                                                       .srcSubpass = VK_SUBPASS_EXTERNAL,
+                                                                       .dstSubpass = 0,
+                                                                       .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                                       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                                       .srcAccessMask = 0,
+                                                                       .dstAccessMask = 0,
+                                                                       .dependencyFlags = 0
+                                                               },
+                                                               {
+                                                                       .srcSubpass = 0,
+                                                                       .dstSubpass = VK_SUBPASS_EXTERNAL,
+                                                                       .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                                       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                                       .srcAccessMask = 0,
+                                                                       .dstAccessMask = 0,
+                                                                       .dependencyFlags = 0
+                                                               }
+                                                       },
+                                                       }, &device->meta_state.alloc, &device->meta_state.blit2d_depth_only_rp[ds_layout]);
+               }
        }
 
        const VkGraphicsPipelineCreateInfo vk_pipeline_info = {
@@ -957,7 +1062,7 @@ blit2d_init_depth_only_pipeline(struct radv_device *device,
                },
                .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
                        .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-                       .rasterizationSamples = 1,
+                       .rasterizationSamples = 1 << log2_samples,
                        .sampleShadingEnable = false,
                        .pSampleMask = (VkSampleMask[]) { UINT32_MAX },
                },
@@ -988,8 +1093,8 @@ blit2d_init_depth_only_pipeline(struct radv_device *device,
                        },
                },
                .flags = 0,
-               .layout = device->meta_state.blit2d.p_layouts[src_type],
-               .renderPass = device->meta_state.blit2d.depth_only_rp,
+               .layout = device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+               .renderPass = device->meta_state.blit2d_depth_only_rp[0],
                .subpass = 0,
        };
 
@@ -1001,28 +1106,40 @@ blit2d_init_depth_only_pipeline(struct radv_device *device,
                                               radv_pipeline_cache_to_handle(&device->meta_state.cache),
                                               &vk_pipeline_info, &radv_pipeline_info,
                                               &device->meta_state.alloc,
-                                              &device->meta_state.blit2d.depth_only_pipeline[src_type]);
+                                              &device->meta_state.blit2d[log2_samples].depth_only_pipeline[src_type]);
 
 
        ralloc_free(vs.nir);
        ralloc_free(fs.nir);
 
+       mtx_unlock(&device->meta_state.mtx);
        return result;
 }
 
 static VkResult
 blit2d_init_stencil_only_pipeline(struct radv_device *device,
-                                 enum blit2d_src_type src_type)
+                                 enum blit2d_src_type src_type,
+                                 uint32_t log2_samples)
 {
        VkResult result;
        const char *name;
 
+       mtx_lock(&device->meta_state.mtx);
+       if (device->meta_state.blit2d[log2_samples].stencil_only_pipeline[src_type]) {
+               mtx_unlock(&device->meta_state.mtx);
+               return VK_SUCCESS;
+       }
+
        texel_fetch_build_func src_func;
        switch(src_type) {
        case BLIT2D_SRC_TYPE_IMAGE:
                src_func = build_nir_texel_fetch;
                name = "meta_blit2d_stencil_image_fs";
                break;
+       case BLIT2D_SRC_TYPE_IMAGE_3D:
+               src_func = build_nir_texel_fetch;
+               name = "meta_blit3d_stencil_image_fs";
+               break;
        case BLIT2D_SRC_TYPE_BUFFER:
                src_func = build_nir_buffer_fetch;
                name = "meta_blit2d_stencil_buffer_fs";
@@ -1035,7 +1152,7 @@ blit2d_init_stencil_only_pipeline(struct radv_device *device,
        const VkPipelineVertexInputStateCreateInfo *vi_create_info;
        struct radv_shader_module fs = { .nir = NULL };
 
-       fs.nir = build_nir_copy_fragment_shader_stencil(device, src_func, name);
+       fs.nir = build_nir_copy_fragment_shader_stencil(device, src_func, name, src_type == BLIT2D_SRC_TYPE_IMAGE_3D, log2_samples > 0);
        vi_create_info = &normal_vi_create_info;
 
        struct radv_shader_module vs = {
@@ -1058,34 +1175,57 @@ blit2d_init_stencil_only_pipeline(struct radv_device *device,
                },
        };
 
-       if (!device->meta_state.blit2d.stencil_only_rp) {
-               result = radv_CreateRenderPass(radv_device_to_handle(device),
-                                              &(VkRenderPassCreateInfo) {
-                                                      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+       for (enum radv_blit_ds_layout ds_layout = RADV_BLIT_DS_LAYOUT_TILE_ENABLE; ds_layout < RADV_BLIT_DS_LAYOUT_COUNT; ds_layout++) {
+               if (!device->meta_state.blit2d_stencil_only_rp[ds_layout]) {
+                       VkImageLayout layout = radv_meta_blit_ds_to_layout(ds_layout);
+                       result = radv_CreateRenderPass(radv_device_to_handle(device),
+                                                      &(VkRenderPassCreateInfo) {
+                                                              .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
                                                               .attachmentCount = 1,
                                                               .pAttachments = &(VkAttachmentDescription) {
-                                                              .format = 0,
-                                                              .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
-                                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                                              .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                              .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      },
-                                                      .subpassCount = 1,
-                                                      .pSubpasses = &(VkSubpassDescription) {
-                                                      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                      .inputAttachmentCount = 0,
-                                                      .colorAttachmentCount = 0,
-                                                      .pColorAttachments = NULL,
-                                                      .pResolveAttachments = NULL,
-                                                      .pDepthStencilAttachment = &(VkAttachmentReference) {
-                                                              .attachment = 0,
-                                                              .layout = VK_IMAGE_LAYOUT_GENERAL,
-                                                      },
-                                                      .preserveAttachmentCount = 1,
-                                                      .pPreserveAttachments = (uint32_t[]) { 0 },
-                                              },
-                                                               .dependencyCount = 0,
-                                                }, &device->meta_state.alloc, &device->meta_state.blit2d.stencil_only_rp);
+                                                                      .format = VK_FORMAT_S8_UINT,
+                                                                      .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
+                                                                      .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                                                      .initialLayout = layout,
+                                                                      .finalLayout = layout,
+                                                              },
+                                                              .subpassCount = 1,
+                                                              .pSubpasses = &(VkSubpassDescription) {
+                                                                      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                                                      .inputAttachmentCount = 0,
+                                                                      .colorAttachmentCount = 0,
+                                                                      .pColorAttachments = NULL,
+                                                                      .pResolveAttachments = NULL,
+                                                                      .pDepthStencilAttachment = &(VkAttachmentReference) {
+                                                                              .attachment = 0,
+                                                                              .layout = layout,
+                                                                      },
+                                                                      .preserveAttachmentCount = 0,
+                                                                      .pPreserveAttachments = NULL,
+                                                              },
+                                                              .dependencyCount = 2,
+                                                              .pDependencies = (VkSubpassDependency[]) {
+                                                               {
+                                                                       .srcSubpass = VK_SUBPASS_EXTERNAL,
+                                                                       .dstSubpass = 0,
+                                                                       .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                                       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                                       .srcAccessMask = 0,
+                                                                       .dstAccessMask = 0,
+                                                                       .dependencyFlags = 0
+                                                               },
+                                                               {
+                                                                       .srcSubpass = 0,
+                                                                       .dstSubpass = VK_SUBPASS_EXTERNAL,
+                                                                       .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                                                                       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                                       .srcAccessMask = 0,
+                                                                       .dstAccessMask = 0,
+                                                                       .dependencyFlags = 0
+                                                               }
+                                                       },
+                                                      }, &device->meta_state.alloc, &device->meta_state.blit2d_stencil_only_rp[ds_layout]);
+               }
        }
 
        const VkGraphicsPipelineCreateInfo vk_pipeline_info = {
@@ -1112,7 +1252,7 @@ blit2d_init_stencil_only_pipeline(struct radv_device *device,
                },
                .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
                        .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-                       .rasterizationSamples = 1,
+                       .rasterizationSamples = 1 << log2_samples,
                        .sampleShadingEnable = false,
                        .pSampleMask = (VkSampleMask[]) { UINT32_MAX },
                },
@@ -1159,8 +1299,8 @@ blit2d_init_stencil_only_pipeline(struct radv_device *device,
                        },
                },
                .flags = 0,
-               .layout = device->meta_state.blit2d.p_layouts[src_type],
-               .renderPass = device->meta_state.blit2d.stencil_only_rp,
+               .layout = device->meta_state.blit2d[log2_samples].p_layouts[src_type],
+               .renderPass = device->meta_state.blit2d_stencil_only_rp[0],
                .subpass = 0,
        };
 
@@ -1172,50 +1312,44 @@ blit2d_init_stencil_only_pipeline(struct radv_device *device,
                                               radv_pipeline_cache_to_handle(&device->meta_state.cache),
                                               &vk_pipeline_info, &radv_pipeline_info,
                                               &device->meta_state.alloc,
-                                              &device->meta_state.blit2d.stencil_only_pipeline[src_type]);
+                                              &device->meta_state.blit2d[log2_samples].stencil_only_pipeline[src_type]);
 
 
        ralloc_free(vs.nir);
        ralloc_free(fs.nir);
 
+       mtx_unlock(&device->meta_state.mtx);
        return result;
 }
 
-static VkFormat pipeline_formats[] = {
-   VK_FORMAT_R8G8B8A8_UNORM,
-   VK_FORMAT_R8G8B8A8_UINT,
-   VK_FORMAT_R8G8B8A8_SINT,
-   VK_FORMAT_R16G16B16A16_UNORM,
-   VK_FORMAT_R16G16B16A16_SNORM,
-   VK_FORMAT_R16G16B16A16_UINT,
-   VK_FORMAT_R16G16B16A16_SINT,
-   VK_FORMAT_R32_SFLOAT,
-   VK_FORMAT_R32G32_SFLOAT,
-   VK_FORMAT_R32G32B32A32_SFLOAT
-};
-
-VkResult
-radv_device_init_meta_blit2d_state(struct radv_device *device)
+static VkResult
+meta_blit2d_create_pipe_layout(struct radv_device *device,
+                              int idx,
+                              uint32_t log2_samples)
 {
        VkResult result;
-
-       zero(device->meta_state.blit2d);
+       VkDescriptorType desc_type = (idx == BLIT2D_SRC_TYPE_BUFFER) ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+       const VkPushConstantRange push_constant_ranges[] = {
+               {VK_SHADER_STAGE_VERTEX_BIT, 0, 16},
+               {VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4},
+       };
+       int num_push_constant_range = (idx != BLIT2D_SRC_TYPE_IMAGE || log2_samples > 0) ? 2 : 1;
 
        result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
                                                &(VkDescriptorSetLayoutCreateInfo) {
                                                        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                                                        .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
-                                                               .bindingCount = 1,
-                                                               .pBindings = (VkDescriptorSetLayoutBinding[]) {
-                                                               {
-                                                                       .binding = 0,
-                                                                       .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
-                                                                       .descriptorCount = 1,
-                                                                       .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
-                                                                       .pImmutableSamplers = NULL
-                                                               },
+                                                       .bindingCount = 1,
+                                                       .pBindings = (VkDescriptorSetLayoutBinding[]) {
+                                                       {
+                                                               .binding = 0,
+                                                               .descriptorType = desc_type,
+                                                               .descriptorCount = 1,
+                                                               .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+                                                               .pImmutableSamplers = NULL
+                                                       },
                                                        }
-                                               }, &device->meta_state.alloc, &device->meta_state.blit2d.ds_layouts[BLIT2D_SRC_TYPE_IMAGE]);
+                                               }, &device->meta_state.alloc, &device->meta_state.blit2d[log2_samples].ds_layouts[idx]);
        if (result != VK_SUCCESS)
                goto fail;
 
@@ -1223,57 +1357,54 @@ radv_device_init_meta_blit2d_state(struct radv_device *device)
                                           &(VkPipelineLayoutCreateInfo) {
                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                                                           .setLayoutCount = 1,
-                                                          .pSetLayouts = &device->meta_state.blit2d.ds_layouts[BLIT2D_SRC_TYPE_IMAGE],
+                                                          .pSetLayouts = &device->meta_state.blit2d[log2_samples].ds_layouts[idx],
+                                                          .pushConstantRangeCount = num_push_constant_range,
+                                                          .pPushConstantRanges = push_constant_ranges,
                                                           },
-                                          &device->meta_state.alloc, &device->meta_state.blit2d.p_layouts[BLIT2D_SRC_TYPE_IMAGE]);
+                                          &device->meta_state.alloc, &device->meta_state.blit2d[log2_samples].p_layouts[idx]);
        if (result != VK_SUCCESS)
                goto fail;
+       return VK_SUCCESS;
+fail:
+       return result;
+}
 
-       result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
-                                               &(VkDescriptorSetLayoutCreateInfo) {
-                                                       .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-                                                       .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
-                                                               .bindingCount = 1,
-                                                               .pBindings = (VkDescriptorSetLayoutBinding[]) {
-                                                               {
-                                                                       .binding = 0,
-                                                                       .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
-                                                                       .descriptorCount = 1,
-                                                                       .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
-                                                                       .pImmutableSamplers = NULL
-                                                               },
-                                                       }
-                                               }, &device->meta_state.alloc, &device->meta_state.blit2d.ds_layouts[BLIT2D_SRC_TYPE_BUFFER]);
-       if (result != VK_SUCCESS)
-               goto fail;
+VkResult
+radv_device_init_meta_blit2d_state(struct radv_device *device, bool on_demand)
+{
+       VkResult result;
+       bool create_3d = device->physical_device->rad_info.chip_class >= GFX9;
 
-       const VkPushConstantRange push_constant_range = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4};
-       result = radv_CreatePipelineLayout(radv_device_to_handle(device),
-                                          &(VkPipelineLayoutCreateInfo) {
-                                                  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-                                                  .setLayoutCount = 1,
-                                                  .pSetLayouts = &device->meta_state.blit2d.ds_layouts[BLIT2D_SRC_TYPE_BUFFER],
-                                                  .pushConstantRangeCount = 1,
-                                                  .pPushConstantRanges = &push_constant_range,
-                                          },
-                                          &device->meta_state.alloc, &device->meta_state.blit2d.p_layouts[BLIT2D_SRC_TYPE_BUFFER]);
-       if (result != VK_SUCCESS)
-               goto fail;
+       for (unsigned log2_samples = 0; log2_samples < MAX_SAMPLES_LOG2; log2_samples++) {
+               for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
+                       if (src == BLIT2D_SRC_TYPE_IMAGE_3D && !create_3d)
+                               continue;
 
-       for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
-               for (unsigned j = 0; j < ARRAY_SIZE(pipeline_formats); ++j) {
-                       result = blit2d_init_color_pipeline(device, src, pipeline_formats[j]);
+                       /* Don't need to handle copies between buffers and multisample images. */
+                       if (src == BLIT2D_SRC_TYPE_BUFFER && log2_samples > 0)
+                               continue;
+
+                       result = meta_blit2d_create_pipe_layout(device, src, log2_samples);
                        if (result != VK_SUCCESS)
                                goto fail;
-               }
 
-               result = blit2d_init_depth_only_pipeline(device, src);
-               if (result != VK_SUCCESS)
-                       goto fail;
+                       if (on_demand)
+                               continue;
 
-               result = blit2d_init_stencil_only_pipeline(device, src);
-               if (result != VK_SUCCESS)
-                       goto fail;
+                       for (unsigned j = 0; j < NUM_META_FS_KEYS; ++j) {
+                               result = blit2d_init_color_pipeline(device, src, radv_fs_key_format_exemplars[j], log2_samples);
+                               if (result != VK_SUCCESS)
+                                       goto fail;
+                       }
+
+                       result = blit2d_init_depth_only_pipeline(device, src, log2_samples);
+                       if (result != VK_SUCCESS)
+                               goto fail;
+
+                       result = blit2d_init_stencil_only_pipeline(device, src, log2_samples);
+                       if (result != VK_SUCCESS)
+                               goto fail;
+               }
        }
 
        return VK_SUCCESS;