radv: use a 16 bytes array for the sampled/storage image descriptors
[mesa.git] / src / amd / vulkan / radv_meta_clear.c
index d007f97b30e3ba516c3531ad3c1526e4075a73cd..b42ecedfc9809d15ad5ffb14986e203987e9a2ee 100644 (file)
@@ -21,6 +21,7 @@
  * IN THE SOFTWARE.
  */
 
+#include "radv_debug.h"
 #include "radv_meta.h"
 #include "radv_private.h"
 #include "nir/nir_builder.h"
@@ -102,7 +103,7 @@ create_pipeline(struct radv_device *device,
                const VkPipelineLayout layout,
                const struct radv_graphics_pipeline_create_info *extra,
                 const VkAllocationCallbacks *alloc,
-                struct radv_pipeline **pipeline)
+               VkPipeline *pipeline)
 {
        VkDevice device_h = radv_device_to_handle(device);
        VkResult result;
@@ -110,7 +111,6 @@ create_pipeline(struct radv_device *device,
        struct radv_shader_module vs_m = { .nir = vs_nir };
        struct radv_shader_module fs_m = { .nir = fs_nir };
 
-       VkPipeline pipeline_h = VK_NULL_HANDLE;
        result = radv_graphics_pipeline_create(device_h,
                                               radv_pipeline_cache_to_handle(&device->meta_state.cache),
                                               &(VkGraphicsPipelineCreateInfo) {
@@ -186,13 +186,11 @@ create_pipeline(struct radv_device *device,
                                                },
                                               extra,
                                               alloc,
-                                              &pipeline_h);
+                                              pipeline);
 
        ralloc_free(vs_nir);
        ralloc_free(fs_nir);
 
-       *pipeline = radv_pipeline_from_handle(pipeline_h);
-
        return result;
 }
 
@@ -239,7 +237,7 @@ static VkResult
 create_color_pipeline(struct radv_device *device,
                      uint32_t samples,
                       uint32_t frag_output,
-                      struct radv_pipeline **pipeline,
+                     VkPipeline *pipeline,
                      VkRenderPass pass)
 {
        struct nir_shader *vs_nir;
@@ -289,25 +287,6 @@ create_color_pipeline(struct radv_device *device,
        return result;
 }
 
-static void
-destroy_pipeline(struct radv_device *device, struct radv_pipeline *pipeline)
-{
-       if (!pipeline)
-               return;
-
-       radv_DestroyPipeline(radv_device_to_handle(device),
-                                  radv_pipeline_to_handle(pipeline),
-                                  &device->meta_state.alloc);
-
-}
-
-static void
-destroy_render_pass(struct radv_device *device, VkRenderPass renderpass)
-{
-       radv_DestroyRenderPass(radv_device_to_handle(device), renderpass,
-                                    &device->meta_state.alloc);
-}
-
 void
 radv_device_finish_meta_clear_state(struct radv_device *device)
 {
@@ -315,16 +294,28 @@ radv_device_finish_meta_clear_state(struct radv_device *device)
 
        for (uint32_t i = 0; i < ARRAY_SIZE(state->clear); ++i) {
                for (uint32_t j = 0; j < ARRAY_SIZE(state->clear[i].color_pipelines); ++j) {
-                       destroy_pipeline(device, state->clear[i].color_pipelines[j]);
-                       destroy_render_pass(device, state->clear[i].render_pass[j]);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->clear[i].color_pipelines[j],
+                                            &state->alloc);
+                       radv_DestroyRenderPass(radv_device_to_handle(device),
+                                              state->clear[i].render_pass[j],
+                                              &state->alloc);
                }
 
                for (uint32_t j = 0; j < NUM_DEPTH_CLEAR_PIPELINES; j++) {
-                       destroy_pipeline(device, state->clear[i].depth_only_pipeline[j]);
-                       destroy_pipeline(device, state->clear[i].stencil_only_pipeline[j]);
-                       destroy_pipeline(device, state->clear[i].depthstencil_pipeline[j]);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->clear[i].depth_only_pipeline[j],
+                                            &state->alloc);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->clear[i].stencil_only_pipeline[j],
+                                            &state->alloc);
+                       radv_DestroyPipeline(radv_device_to_handle(device),
+                                            state->clear[i].depthstencil_pipeline[j],
+                                            &state->alloc);
                }
-               destroy_render_pass(device, state->clear[i].depthstencil_rp);
+               radv_DestroyRenderPass(radv_device_to_handle(device),
+                                     state->clear[i].depthstencil_rp,
+                                     &state->alloc);
        }
        radv_DestroyPipelineLayout(radv_device_to_handle(device),
                                   state->clear_color_p_layout,
@@ -337,7 +328,8 @@ radv_device_finish_meta_clear_state(struct radv_device *device)
 static void
 emit_color_clear(struct radv_cmd_buffer *cmd_buffer,
                  const VkClearAttachment *clear_att,
-                 const VkClearRect *clear_rect)
+                 const VkClearRect *clear_rect,
+                 uint32_t view_mask)
 {
        struct radv_device *device = cmd_buffer->device;
        const struct radv_subpass *subpass = cmd_buffer->state.subpass;
@@ -348,18 +340,16 @@ emit_color_clear(struct radv_cmd_buffer *cmd_buffer,
        const uint32_t samples = iview->image->info.samples;
        const uint32_t samples_log2 = ffs(samples) - 1;
        unsigned fs_key = radv_format_meta_fs_key(iview->vk_format);
-       struct radv_pipeline *pipeline;
        VkClearColorValue clear_value = clear_att->clearValue.color;
        VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
-       VkPipeline pipeline_h;
+       VkPipeline pipeline;
 
        if (fs_key == -1) {
                radv_finishme("color clears incomplete");
                return;
        }
-       pipeline = device->meta_state.clear[samples_log2].color_pipelines[fs_key];
-       pipeline_h = radv_pipeline_to_handle(pipeline);
 
+       pipeline = device->meta_state.clear[samples_log2].color_pipelines[fs_key];
        if (!pipeline) {
                radv_finishme("color clears incomplete");
                return;
@@ -384,10 +374,8 @@ emit_color_clear(struct radv_cmd_buffer *cmd_buffer,
 
        radv_cmd_buffer_set_subpass(cmd_buffer, &clear_subpass, false);
 
-       if (cmd_buffer->state.pipeline != pipeline) {
-               radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                          pipeline_h);
-       }
+       radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                            pipeline);
 
        radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
                        .x = clear_rect->rect.offset.x,
@@ -400,7 +388,13 @@ emit_color_clear(struct radv_cmd_buffer *cmd_buffer,
 
        radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &clear_rect->rect);
 
-       radv_CmdDraw(cmd_buffer_h, 3, clear_rect->layerCount, 0, clear_rect->baseArrayLayer);
+       if (view_mask) {
+               unsigned i;
+               for_each_bit(i, view_mask)
+                       radv_CmdDraw(cmd_buffer_h, 3, 1, 0, i);
+       } else {
+               radv_CmdDraw(cmd_buffer_h, 3, clear_rect->layerCount, 0, clear_rect->baseArrayLayer);
+       }
 
        radv_cmd_buffer_set_subpass(cmd_buffer, subpass, false);
 }
@@ -490,7 +484,7 @@ create_depthstencil_pipeline(struct radv_device *device,
                              VkImageAspectFlags aspects,
                             uint32_t samples,
                             int index,
-                             struct radv_pipeline **pipeline,
+                            VkPipeline *pipeline,
                             VkRenderPass render_pass)
 {
        struct nir_shader *vs_nir, *fs_nir;
@@ -547,8 +541,10 @@ create_depthstencil_pipeline(struct radv_device *device,
 
 static bool depth_view_can_fast_clear(struct radv_cmd_buffer *cmd_buffer,
                                      const struct radv_image_view *iview,
+                                     VkImageAspectFlags aspects,
                                      VkImageLayout layout,
-                                     const VkClearRect *clear_rect)
+                                     const VkClearRect *clear_rect,
+                                     VkClearDepthStencilValue clear_value)
 {
        uint32_t queue_mask = radv_image_queue_family_mask(iview->image,
                                                           cmd_buffer->queue_family_index,
@@ -557,6 +553,11 @@ static bool depth_view_can_fast_clear(struct radv_cmd_buffer *cmd_buffer,
            clear_rect->rect.extent.width != iview->extent.width ||
            clear_rect->rect.extent.height != iview->extent.height)
                return false;
+       if (iview->image->tc_compatible_htile &&
+           (((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) && clear_value.depth != 0.0 &&
+             clear_value.depth != 1.0) ||
+            ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) && clear_value.stencil != 0)))
+               return false;
        if (iview->image->surface.htile_size &&
            iview->base_mip == 0 &&
            iview->base_layer == 0 &&
@@ -566,7 +567,7 @@ static bool depth_view_can_fast_clear(struct radv_cmd_buffer *cmd_buffer,
        return false;
 }
 
-static struct radv_pipeline *
+static VkPipeline
 pick_depthstencil_pipeline(struct radv_cmd_buffer *cmd_buffer,
                           struct radv_meta_state *meta_state,
                           const struct radv_image_view *iview,
@@ -576,7 +577,7 @@ pick_depthstencil_pipeline(struct radv_cmd_buffer *cmd_buffer,
                           const VkClearRect *clear_rect,
                           VkClearDepthStencilValue clear_value)
 {
-       bool fast = depth_view_can_fast_clear(cmd_buffer, iview, layout, clear_rect);
+       bool fast = depth_view_can_fast_clear(cmd_buffer, iview, aspects, layout, clear_rect, clear_value);
        int index = DEPTH_CLEAR_SLOW;
 
        if (fast) {
@@ -613,10 +614,6 @@ emit_depthstencil_clear(struct radv_cmd_buffer *cmd_buffer,
        const uint32_t samples_log2 = ffs(samples) - 1;
        VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
 
-       assert(aspects == VK_IMAGE_ASPECT_DEPTH_BIT ||
-              aspects == VK_IMAGE_ASPECT_STENCIL_BIT ||
-              aspects == (VK_IMAGE_ASPECT_DEPTH_BIT |
-                          VK_IMAGE_ASPECT_STENCIL_BIT));
        assert(pass_att != VK_ATTACHMENT_UNUSED);
 
        if (!(aspects & VK_IMAGE_ASPECT_DEPTH_BIT))
@@ -632,20 +629,21 @@ emit_depthstencil_clear(struct radv_cmd_buffer *cmd_buffer,
                                                  clear_value.stencil);
        }
 
-       struct radv_pipeline *pipeline = pick_depthstencil_pipeline(cmd_buffer,
-                                                                   meta_state,
-                                                                   iview,
-                                                                   samples_log2,
-                                                                   aspects,
-                                                                   subpass->depth_stencil_attachment.layout,
-                                                                   clear_rect,
-                                                                   clear_value);
-       if (cmd_buffer->state.pipeline != pipeline) {
-               radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                          radv_pipeline_to_handle(pipeline));
-       }
-
-       if (depth_view_can_fast_clear(cmd_buffer, iview, subpass->depth_stencil_attachment.layout, clear_rect))
+       VkPipeline pipeline = pick_depthstencil_pipeline(cmd_buffer,
+                                                        meta_state,
+                                                        iview,
+                                                        samples_log2,
+                                                        aspects,
+                                                        subpass->depth_stencil_attachment.layout,
+                                                        clear_rect,
+                                                        clear_value);
+
+       radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                            pipeline);
+
+       if (depth_view_can_fast_clear(cmd_buffer, iview, aspects,
+                                     subpass->depth_stencil_attachment.layout,
+                                     clear_rect, clear_value))
                radv_set_depth_clear_regs(cmd_buffer, iview->image, clear_value, aspects);
 
        radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
@@ -676,12 +674,12 @@ emit_fast_htile_clear(struct radv_cmd_buffer *cmd_buffer,
        const struct radv_image_view *iview = fb->attachments[pass_att].attachment;
        VkClearDepthStencilValue clear_value = clear_att->clearValue.depthStencil;
        VkImageAspectFlags aspects = clear_att->aspectMask;
-       uint32_t clear_word;
+       uint32_t clear_word, flush_bits;
 
        if (!iview->image->surface.htile_size)
                return false;
 
-       if (cmd_buffer->device->debug_flags & RADV_DEBUG_NO_FAST_CLEARS)
+       if (cmd_buffer->device->instance->debug_flags & RADV_DEBUG_NO_FAST_CLEARS)
                return false;
 
        if (!radv_layout_is_htile_compressed(iview->image, image_layout, radv_image_queue_family_mask(iview->image, cmd_buffer->queue_family_index, cmd_buffer->queue_family_index)))
@@ -697,9 +695,6 @@ emit_fast_htile_clear(struct radv_cmd_buffer *cmd_buffer,
        if (iview->image->info.array_size != iview->layer_count)
                goto fail;
 
-       if (iview->image->info.levels > 1)
-               goto fail;
-
        if (!radv_image_extent_compare(iview->image, &iview->extent))
                goto fail;
 
@@ -731,20 +726,17 @@ emit_fast_htile_clear(struct radv_cmd_buffer *cmd_buffer,
                cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB |
                                                RADV_CMD_FLAG_FLUSH_AND_INV_DB_META;
 
-       radv_fill_buffer(cmd_buffer, iview->image->bo,
-                        iview->image->offset + iview->image->htile_offset,
-                        iview->image->surface.htile_size, clear_word);
-
+       flush_bits = radv_fill_buffer(cmd_buffer, iview->image->bo,
+                                     iview->image->offset + iview->image->htile_offset,
+                                     iview->image->surface.htile_size, clear_word);
 
        radv_set_depth_clear_regs(cmd_buffer, iview->image, clear_value, aspects);
-       if (post_flush)
-               *post_flush |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                              RADV_CMD_FLAG_INV_VMEM_L1 |
-                              RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
-       else
-               cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                                               RADV_CMD_FLAG_INV_VMEM_L1 |
-                                               RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
+       if (post_flush) {
+               *post_flush |= flush_bits;
+       } else {
+               cmd_buffer->state.flush_bits |= flush_bits;
+       }
+
        return true;
 fail:
        return false;
@@ -754,6 +746,8 @@ static VkFormat pipeline_formats[] = {
        VK_FORMAT_R8G8B8A8_UNORM,
        VK_FORMAT_R8G8B8A8_UINT,
        VK_FORMAT_R8G8B8A8_SINT,
+       VK_FORMAT_A2R10G10B10_UINT_PACK32,
+       VK_FORMAT_A2R10G10B10_SINT_PACK32,
        VK_FORMAT_R16G16B16A16_UNORM,
        VK_FORMAT_R16G16B16A16_SNORM,
        VK_FORMAT_R16G16B16A16_UINT,
@@ -769,8 +763,6 @@ radv_device_init_meta_clear_state(struct radv_device *device)
        VkResult res;
        struct radv_meta_state *state = &device->meta_state;
 
-       memset(&device->meta_state.clear, 0, sizeof(device->meta_state.clear));
-
        VkPipelineLayoutCreateInfo pl_color_create_info = {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                .setLayoutCount = 0,
@@ -943,7 +935,8 @@ emit_fast_color_clear(struct radv_cmd_buffer *cmd_buffer,
                      const VkClearAttachment *clear_att,
                      const VkClearRect *clear_rect,
                      enum radv_cmd_flush_bits *pre_flush,
-                     enum radv_cmd_flush_bits *post_flush)
+                     enum radv_cmd_flush_bits *post_flush,
+                      uint32_t view_mask)
 {
        const struct radv_subpass *subpass = cmd_buffer->state.subpass;
        const uint32_t subpass_att = clear_att->colorAttachment;
@@ -952,13 +945,13 @@ emit_fast_color_clear(struct radv_cmd_buffer *cmd_buffer,
        const struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
        const struct radv_image_view *iview = fb->attachments[pass_att].attachment;
        VkClearColorValue clear_value = clear_att->clearValue.color;
-       uint32_t clear_color[2];
+       uint32_t clear_color[2], flush_bits;
        bool ret;
 
        if (!iview->image->cmask.size && !iview->image->surface.dcc_size)
                return false;
 
-       if (cmd_buffer->device->debug_flags & RADV_DEBUG_NO_FAST_CLEARS)
+       if (cmd_buffer->device->instance->debug_flags & RADV_DEBUG_NO_FAST_CLEARS)
                return false;
 
        if (!radv_layout_can_fast_clear(iview->image, image_layout, radv_image_queue_family_mask(iview->image, cmd_buffer->queue_family_index, cmd_buffer->queue_family_index)))
@@ -977,7 +970,7 @@ emit_fast_color_clear(struct radv_cmd_buffer *cmd_buffer,
        if (iview->image->info.levels > 1)
                goto fail;
 
-       if (iview->image->surface.u.legacy.level[0].mode < RADEON_SURF_MODE_1D)
+       if (iview->image->surface.is_linear)
                goto fail;
        if (!radv_image_extent_compare(iview->image, &iview->extent))
                goto fail;
@@ -987,9 +980,12 @@ emit_fast_color_clear(struct radv_cmd_buffer *cmd_buffer,
            clear_rect->rect.extent.height != iview->image->info.height)
                goto fail;
 
-       if (clear_rect->baseArrayLayer != 0)
+       if (view_mask && (iview->image->info.array_size >= 32 ||
+                        (1u << iview->image->info.array_size) - 1u != view_mask))
                goto fail;
-       if (clear_rect->layerCount != iview->image->info.array_size)
+       if (!view_mask && clear_rect->baseArrayLayer != 0)
+               goto fail;
+       if (!view_mask && clear_rect->layerCount != iview->image->info.array_size)
                goto fail;
 
        /* RB+ doesn't work with CMASK fast clear on Stoney. */
@@ -1018,30 +1014,22 @@ emit_fast_color_clear(struct radv_cmd_buffer *cmd_buffer,
                                             &clear_value, &reset_value,
                                             &can_avoid_fast_clear_elim);
 
-               radv_fill_buffer(cmd_buffer, iview->image->bo,
-                                iview->image->offset + iview->image->dcc_offset,
-                                iview->image->surface.dcc_size, reset_value);
+               flush_bits = radv_fill_buffer(cmd_buffer, iview->image->bo,
+                                             iview->image->offset + iview->image->dcc_offset,
+                                             iview->image->surface.dcc_size, reset_value);
                radv_set_dcc_need_cmask_elim_pred(cmd_buffer, iview->image,
                                                  !can_avoid_fast_clear_elim);
        } else {
-
-               if (iview->image->surface.bpe > 8) {
-                       /* 128 bit formats not supported */
-                       return false;
-               }
-               radv_fill_buffer(cmd_buffer, iview->image->bo,
-                                iview->image->offset + iview->image->cmask.offset,
-                                iview->image->cmask.size, 0);
+               flush_bits = radv_fill_buffer(cmd_buffer, iview->image->bo,
+                                             iview->image->offset + iview->image->cmask.offset,
+                                             iview->image->cmask.size, 0);
        }
 
-       if (post_flush)
-               *post_flush |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                              RADV_CMD_FLAG_INV_VMEM_L1 |
-                              RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
-       else
-               cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                                               RADV_CMD_FLAG_INV_VMEM_L1 |
-                                               RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
+       if (post_flush) {
+               *post_flush |= flush_bits;
+       } else {
+               cmd_buffer->state.flush_bits |= flush_bits;
+       }
 
        radv_set_color_clear_regs(cmd_buffer, iview->image, subpass_att, clear_color);
 
@@ -1058,13 +1046,13 @@ emit_clear(struct radv_cmd_buffer *cmd_buffer,
            const VkClearAttachment *clear_att,
            const VkClearRect *clear_rect,
            enum radv_cmd_flush_bits *pre_flush,
-           enum radv_cmd_flush_bits *post_flush)
+           enum radv_cmd_flush_bits *post_flush,
+           uint32_t view_mask)
 {
        if (clear_att->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
-
                if (!emit_fast_color_clear(cmd_buffer, clear_att, clear_rect,
-                                          pre_flush, post_flush))
-                       emit_color_clear(cmd_buffer, clear_att, clear_rect);
+                                          pre_flush, post_flush, view_mask))
+                       emit_color_clear(cmd_buffer, clear_att, clear_rect, view_mask);
        } else {
                assert(clear_att->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
                                                VK_IMAGE_ASPECT_STENCIL_BIT));
@@ -1074,29 +1062,56 @@ emit_clear(struct radv_cmd_buffer *cmd_buffer,
        }
 }
 
+static inline bool
+radv_attachment_needs_clear(struct radv_cmd_state *cmd_state, uint32_t a)
+{
+       uint32_t view_mask = cmd_state->subpass->view_mask;
+       return (a != VK_ATTACHMENT_UNUSED &&
+               cmd_state->attachments[a].pending_clear_aspects &&
+               (!view_mask || (view_mask & ~cmd_state->attachments[a].cleared_views)));
+}
+
 static bool
-subpass_needs_clear(const struct radv_cmd_buffer *cmd_buffer)
+radv_subpass_needs_clear(struct radv_cmd_buffer *cmd_buffer)
 {
-       const struct radv_cmd_state *cmd_state = &cmd_buffer->state;
-       uint32_t ds;
+       struct radv_cmd_state *cmd_state = &cmd_buffer->state;
+       uint32_t a;
 
        if (!cmd_state->subpass)
                return false;
-       ds = cmd_state->subpass->depth_stencil_attachment.attachment;
+
        for (uint32_t i = 0; i < cmd_state->subpass->color_count; ++i) {
-               uint32_t a = cmd_state->subpass->color_attachments[i].attachment;
-               if (a != VK_ATTACHMENT_UNUSED &&
-                   cmd_state->attachments[a].pending_clear_aspects) {
+               a = cmd_state->subpass->color_attachments[i].attachment;
+               if (radv_attachment_needs_clear(cmd_state, a))
                        return true;
-               }
        }
 
-       if (ds != VK_ATTACHMENT_UNUSED &&
-           cmd_state->attachments[ds].pending_clear_aspects) {
-               return true;
-       }
+       a = cmd_state->subpass->depth_stencil_attachment.attachment;
+       return radv_attachment_needs_clear(cmd_state, a);
+}
 
-       return false;
+static void
+radv_subpass_clear_attachment(struct radv_cmd_buffer *cmd_buffer,
+                             struct radv_attachment_state *attachment,
+                             const VkClearAttachment *clear_att,
+                             enum radv_cmd_flush_bits *pre_flush,
+                             enum radv_cmd_flush_bits *post_flush)
+{
+       struct radv_cmd_state *cmd_state = &cmd_buffer->state;
+       uint32_t view_mask = cmd_state->subpass->view_mask;
+
+       VkClearRect clear_rect = {
+               .rect = cmd_state->render_area,
+               .baseArrayLayer = 0,
+               .layerCount = cmd_state->framebuffer->layers,
+       };
+
+       emit_clear(cmd_buffer, clear_att, &clear_rect, pre_flush, post_flush,
+                  view_mask & ~attachment->cleared_views);
+       if (view_mask)
+               attachment->cleared_views |= view_mask;
+       else
+               attachment->pending_clear_aspects = 0;
 }
 
 /**
@@ -1112,22 +1127,17 @@ radv_cmd_buffer_clear_subpass(struct radv_cmd_buffer *cmd_buffer)
        enum radv_cmd_flush_bits pre_flush = 0;
        enum radv_cmd_flush_bits post_flush = 0;
 
-       if (!subpass_needs_clear(cmd_buffer))
+       if (!radv_subpass_needs_clear(cmd_buffer))
                return;
 
-       radv_meta_save_graphics_reset_vport_scissor_novertex(&saved_state, cmd_buffer);
-
-       VkClearRect clear_rect = {
-               .rect = cmd_state->render_area,
-               .baseArrayLayer = 0,
-               .layerCount = cmd_state->framebuffer->layers,
-       };
+       radv_meta_save(&saved_state, cmd_buffer,
+                      RADV_META_SAVE_GRAPHICS_PIPELINE |
+                      RADV_META_SAVE_CONSTANTS);
 
        for (uint32_t i = 0; i < cmd_state->subpass->color_count; ++i) {
                uint32_t a = cmd_state->subpass->color_attachments[i].attachment;
 
-               if (a == VK_ATTACHMENT_UNUSED ||
-                   !cmd_state->attachments[a].pending_clear_aspects)
+               if (!radv_attachment_needs_clear(cmd_state, a))
                        continue;
 
                assert(cmd_state->attachments[a].pending_clear_aspects ==
@@ -1139,25 +1149,23 @@ radv_cmd_buffer_clear_subpass(struct radv_cmd_buffer *cmd_buffer)
                        .clearValue = cmd_state->attachments[a].clear_value,
                };
 
-               emit_clear(cmd_buffer, &clear_att, &clear_rect, &pre_flush, &post_flush);
-               cmd_state->attachments[a].pending_clear_aspects = 0;
+               radv_subpass_clear_attachment(cmd_buffer,
+                                             &cmd_state->attachments[a],
+                                             &clear_att, &pre_flush,
+                                             &post_flush);
        }
 
        uint32_t ds = cmd_state->subpass->depth_stencil_attachment.attachment;
+       if (radv_attachment_needs_clear(cmd_state, ds)) {
+               VkClearAttachment clear_att = {
+                       .aspectMask = cmd_state->attachments[ds].pending_clear_aspects,
+                       .clearValue = cmd_state->attachments[ds].clear_value,
+               };
 
-       if (ds != VK_ATTACHMENT_UNUSED) {
-
-               if (cmd_state->attachments[ds].pending_clear_aspects) {
-
-                       VkClearAttachment clear_att = {
-                               .aspectMask = cmd_state->attachments[ds].pending_clear_aspects,
-                               .clearValue = cmd_state->attachments[ds].clear_value,
-                       };
-
-                       emit_clear(cmd_buffer, &clear_att, &clear_rect,
-                                  &pre_flush, &post_flush);
-                       cmd_state->attachments[ds].pending_clear_aspects = 0;
-               }
+               radv_subpass_clear_attachment(cmd_buffer,
+                                             &cmd_state->attachments[ds],
+                                             &clear_att, &pre_flush,
+                                             &post_flush);
        }
 
        radv_meta_restore(&saved_state, cmd_buffer);
@@ -1174,6 +1182,9 @@ radv_clear_image_layer(struct radv_cmd_buffer *cmd_buffer,
 {
        VkDevice device_h = radv_device_to_handle(cmd_buffer->device);
        struct radv_image_view iview;
+       uint32_t width = radv_minify(image->info.width, range->baseMipLevel + level);
+       uint32_t height = radv_minify(image->info.height, range->baseMipLevel + level);
+
        radv_image_view_init(&iview, cmd_buffer->device,
                             &(VkImageViewCreateInfo) {
                                     .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@@ -1197,9 +1208,9 @@ radv_clear_image_layer(struct radv_cmd_buffer *cmd_buffer,
                                               .pAttachments = (VkImageView[]) {
                                               radv_image_view_to_handle(&iview),
                                       },
-                                              .width = iview.extent.width,
-                                                       .height = iview.extent.height,
-                                                       .layers = 1
+                                              .width = width,
+                                              .height = height,
+                                              .layers = 1
                               },
                               &cmd_buffer->pool->alloc,
                               &fb);
@@ -1255,8 +1266,8 @@ radv_clear_image_layer(struct radv_cmd_buffer *cmd_buffer,
                                                .renderArea = {
                                                .offset = { 0, 0, },
                                                .extent = {
-                                                       .width = iview.extent.width,
-                                                       .height = iview.extent.height,
+                                                       .width = width,
+                                                       .height = height,
                                                },
                                        },
                                                .renderPass = pass,
@@ -1275,13 +1286,13 @@ radv_clear_image_layer(struct radv_cmd_buffer *cmd_buffer,
        VkClearRect clear_rect = {
                .rect = {
                        .offset = { 0, 0 },
-                       .extent = { iview.extent.width, iview.extent.height },
+                       .extent = { width, height },
                },
                .baseArrayLayer = range->baseArrayLayer,
                .layerCount = 1, /* FINISHME: clear multi-layer framebuffer */
        };
 
-       emit_clear(cmd_buffer, &clear_att, &clear_rect, NULL, NULL);
+       emit_clear(cmd_buffer, &clear_att, &clear_rect, NULL, NULL, 0);
 
        radv_CmdEndRenderPass(radv_cmd_buffer_to_handle(cmd_buffer));
        radv_DestroyRenderPass(device_h, pass,
@@ -1342,11 +1353,6 @@ radv_cmd_clear_image(struct radv_cmd_buffer *cmd_buffer,
        }
 }
 
-union meta_saved_state {
-       struct radv_meta_saved_state gfx;
-       struct radv_meta_saved_compute_state compute;
-};
-
 void radv_CmdClearColorImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     image_h,
@@ -1357,22 +1363,25 @@ void radv_CmdClearColorImage(
 {
        RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
        RADV_FROM_HANDLE(radv_image, image, image_h);
-       union meta_saved_state saved_state;
+       struct radv_meta_saved_state saved_state;
        bool cs = cmd_buffer->queue_family_index == RADV_QUEUE_COMPUTE;
 
-       if (cs)
-               radv_meta_begin_cleari(cmd_buffer, &saved_state.compute);
-       else
-               radv_meta_save_graphics_reset_vport_scissor_novertex(&saved_state.gfx, cmd_buffer);
+       if (cs) {
+               radv_meta_save(&saved_state, cmd_buffer,
+                              RADV_META_SAVE_COMPUTE_PIPELINE |
+                              RADV_META_SAVE_CONSTANTS |
+                              RADV_META_SAVE_DESCRIPTORS);
+       } else {
+               radv_meta_save(&saved_state, cmd_buffer,
+                              RADV_META_SAVE_GRAPHICS_PIPELINE |
+                              RADV_META_SAVE_CONSTANTS);
+       }
 
        radv_cmd_clear_image(cmd_buffer, image, imageLayout,
                             (const VkClearValue *) pColor,
                             rangeCount, pRanges, cs);
 
-       if (cs)
-               radv_meta_end_cleari(cmd_buffer, &saved_state.compute);
-       else
-               radv_meta_restore(&saved_state.gfx, cmd_buffer);
+       radv_meta_restore(&saved_state, cmd_buffer);
 }
 
 void radv_CmdClearDepthStencilImage(
@@ -1387,7 +1396,9 @@ void radv_CmdClearDepthStencilImage(
        RADV_FROM_HANDLE(radv_image, image, image_h);
        struct radv_meta_saved_state saved_state;
 
-       radv_meta_save_graphics_reset_vport_scissor_novertex(&saved_state, cmd_buffer);
+       radv_meta_save(&saved_state, cmd_buffer,
+                      RADV_META_SAVE_GRAPHICS_PIPELINE |
+                      RADV_META_SAVE_CONSTANTS);
 
        radv_cmd_clear_image(cmd_buffer, image, imageLayout,
                             (const VkClearValue *) pDepthStencil,
@@ -1411,14 +1422,17 @@ void radv_CmdClearAttachments(
        if (!cmd_buffer->state.subpass)
                return;
 
-       radv_meta_save_graphics_reset_vport_scissor_novertex(&saved_state, cmd_buffer);
+       radv_meta_save(&saved_state, cmd_buffer,
+                      RADV_META_SAVE_GRAPHICS_PIPELINE |
+                      RADV_META_SAVE_CONSTANTS);
 
        /* FINISHME: We can do better than this dumb loop. It thrashes too much
         * state.
         */
        for (uint32_t a = 0; a < attachmentCount; ++a) {
                for (uint32_t r = 0; r < rectCount; ++r) {
-                       emit_clear(cmd_buffer, &pAttachments[a], &pRects[r], &pre_flush, &post_flush);
+                       emit_clear(cmd_buffer, &pAttachments[a], &pRects[r], &pre_flush, &post_flush,
+                                  cmd_buffer->state.subpass->view_mask);
                }
        }