tu: Handle vkCmdClearAttachments() with sysmem
authorConnor Abbott <cwabbott0@gmail.com>
Thu, 6 Feb 2020 14:55:05 +0000 (15:55 +0100)
committerJonathan Marek <jonathan@marek.ca>
Thu, 13 Feb 2020 02:36:41 +0000 (21:36 -0500)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3713>

src/freedreno/vulkan/tu_blit.h
src/freedreno/vulkan/tu_cmd_buffer.c
src/freedreno/vulkan/tu_meta_clear.c
src/freedreno/vulkan/tu_private.h

index cadcfc0cf294afe90ece8c5a1ebd088fbb2efd9c..6400fa9d2bca9fc589f56de2b39be5f28530ade2 100644 (file)
@@ -102,6 +102,25 @@ tu_blit_surf_whole(struct tu_image *image, int level, int layer)
    });
 }
 
+static inline struct tu_blit_surf
+sysmem_attachment_surf(const struct tu_image_view *view, uint32_t base_layer,
+                       const VkRect2D *rect)
+{
+   return tu_blit_surf_ext(view->image, (VkImageSubresourceLayers) {
+      .mipLevel = view->base_mip,
+      .baseArrayLayer = base_layer,
+   }, (VkOffset3D) {
+      .x = rect->offset.x,
+      .y = rect->offset.y,
+      .z = 0,
+   }, (VkExtent3D) {
+      .width = rect->extent.width,
+      .height = rect->extent.height,
+      .depth = 1,
+   });
+}
+
+
 enum tu_blit_type {
    TU_BLIT_DEFAULT,
    TU_BLIT_COPY,
index e751a6273d09d75e584aa282f4ff1f87ed50238e..0df31a07f2ec0e0699931e5c08bd98817629c4fb 100644 (file)
@@ -848,33 +848,8 @@ tu6_emit_clear_attachment(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
    if (!clear_mask)
       return;
 
-   const struct tu_native_format *format =
-      tu6_get_native_format(iview->vk_format);
-   assert(format && format->rb >= 0);
-
-   tu_cs_emit_regs(cs,
-                   A6XX_RB_BLIT_DST_INFO(.color_format = format->rb));
-
-   tu_cs_emit_regs(cs,
-                   A6XX_RB_BLIT_INFO(.gmem = true,
-                                     .clear_mask = clear_mask));
-
-   tu_cs_emit_regs(cs,
-                   A6XX_RB_BLIT_BASE_GMEM(attachment->gmem_offset));
-
-   tu_cs_emit_regs(cs,
-                   A6XX_RB_UNKNOWN_88D0(0));
-
-   uint32_t clear_vals[4] = { 0 };
-   tu_pack_clear_value(&info->pClearValues[a], iview->vk_format, clear_vals);
-
-   tu_cs_emit_regs(cs,
-                   A6XX_RB_BLIT_CLEAR_COLOR_DW0(clear_vals[0]),
-                   A6XX_RB_BLIT_CLEAR_COLOR_DW1(clear_vals[1]),
-                   A6XX_RB_BLIT_CLEAR_COLOR_DW2(clear_vals[2]),
-                   A6XX_RB_BLIT_CLEAR_COLOR_DW3(clear_vals[3]));
-
-   tu6_emit_blit(cmd, cs);
+   tu_clear_gmem_attachment(cmd, cs, a, clear_mask,
+                            &info->pClearValues[a]);
 }
 
 static void
@@ -1320,27 +1295,10 @@ tu6_emit_binning_pass(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
    cmd->wait_for_idle = false;
 }
 
-static inline struct tu_blit_surf
-sysmem_clear_surf(const struct tu_image_view *view, const VkRect2D *render_area)
-{
-   return tu_blit_surf_ext(view->image, (VkImageSubresourceLayers) {
-      .mipLevel = view->base_mip,
-      .baseArrayLayer = view->base_layer,
-   }, (VkOffset3D) {
-      .x = render_area->offset.x,
-      .y = render_area->offset.y,
-      .z = 0,
-   }, (VkExtent3D) {
-      .width = render_area->extent.width,
-      .height = render_area->extent.height,
-      .depth = 1,
-   });
-}
-
 static void
-tu6_emit_sysmem_clear_attachment(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
-                                 uint32_t a,
-                                 const VkRenderPassBeginInfo *info)
+tu_emit_sysmem_clear_attachment(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
+                                uint32_t a,
+                                const VkRenderPassBeginInfo *info)
 {
    const struct tu_framebuffer *fb = cmd->state.framebuffer;
    const struct tu_image_view *iview = fb->attachments[a].attachment;
@@ -1352,8 +1310,6 @@ tu6_emit_sysmem_clear_attachment(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
    if (attachment->gmem_offset < 0)
       return;
 
-   uint32_t clear_vals[4] = { 0 };
-
    if (attachment->load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
       clear_mask = 0xf;
    }
@@ -1369,20 +1325,11 @@ tu6_emit_sysmem_clear_attachment(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
    if (!clear_mask)
       return;
 
-   if (iview->aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT |
-                             VK_IMAGE_ASPECT_STENCIL_BIT)) {
-      tu_2d_clear_zs(&info->pClearValues[a].depthStencil, iview->vk_format,
-                     clear_vals);
-   } else {
-      tu_2d_clear_color(&info->pClearValues[a].color, iview->vk_format,
-                        clear_vals);
-   }
-
-   tu_blit(cmd, cs, &(struct tu_blit) {
-      .dst = sysmem_clear_surf(iview, &info->renderArea),
-      .layers = iview->layer_count,
-      .clear_value = { clear_vals[0], clear_vals[1], clear_vals[2], clear_vals[3] },
-      .type = TU_BLIT_CLEAR,
+   tu_clear_sysmem_attachment(cmd, cs, a,
+                              &info->pClearValues[a], &(struct VkClearRect) {
+      .rect = info->renderArea,
+      .baseArrayLayer = iview->base_layer,
+      .layerCount = iview->layer_count,
    });
 }
 
@@ -1405,7 +1352,7 @@ tu_cmd_prepare_sysmem_clear_ib(struct tu_cmd_buffer *cmd,
    }
 
    for (uint32_t i = 0; i < cmd->state.pass->attachment_count; ++i)
-      tu6_emit_sysmem_clear_attachment(cmd, &sub_cs, i, info);
+      tu_emit_sysmem_clear_attachment(cmd, &sub_cs, i, info);
 
    /* TODO: We shouldn't need this flush, but without it we'd have an empty IB
     * when nothing clears which we currently can't handle.
@@ -2599,9 +2546,9 @@ tu_CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents)
    struct tu_cs *cs = &cmd->draw_cs;
 
    VkResult result = tu_cs_reserve_space(cmd->device, cs, 1024);
-   if (result != VK_SUCCESS) {
-      cmd->record_result = result;
-      return;
+    if (result != VK_SUCCESS) {
+       cmd->record_result = result;
+       return;
    }
 
    const struct tu_subpass *subpass = cmd->state.subpass++;
index 478b7ce9aa3b4072c1c00851c2420798242dbb66..7d24c737cc7b98f583cd81d1e0d9ccc9888c21e0 100644 (file)
@@ -92,6 +92,74 @@ tu_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer,
       clear_image(cmdbuf, image, clear_value, pRanges + i);
 }
 
+void
+tu_clear_sysmem_attachment(struct tu_cmd_buffer *cmd,
+                           struct tu_cs *cs,
+                           uint32_t attachment,
+                           const VkClearValue *value,
+                           const VkClearRect *rect)
+{
+   if (!cmd->state.framebuffer) {
+      tu_finishme("sysmem CmdClearAttachments in secondary command buffer");
+      return;
+   }
+
+   const struct tu_image_view *iview =
+      cmd->state.framebuffer->attachments[attachment].attachment;
+
+   uint32_t clear_vals[4] = { 0 };
+   if (iview->aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT |
+                             VK_IMAGE_ASPECT_STENCIL_BIT)) {
+      tu_2d_clear_zs(&value->depthStencil, iview->vk_format,
+                     clear_vals);
+   } else {
+      tu_2d_clear_color(&value->color, iview->vk_format,
+                        clear_vals);
+   }
+
+   tu_blit(cmd, cs, &(struct tu_blit) {
+      .dst = sysmem_attachment_surf(iview, rect->baseArrayLayer, &rect->rect),
+      .layers = rect->layerCount,
+      .clear_value = { clear_vals[0], clear_vals[1], clear_vals[2], clear_vals[3] },
+      .type = TU_BLIT_CLEAR,
+   });
+}
+
+void
+tu_clear_gmem_attachment(struct tu_cmd_buffer *cmd,
+                         struct tu_cs *cs,
+                         uint32_t attachment,
+                         uint8_t component_mask,
+                         const VkClearValue *value)
+{
+   VkFormat fmt = cmd->state.pass->attachments[attachment].format;
+   const struct tu_native_format *format = tu6_get_native_format(fmt);
+   assert(format && format->rb >= 0);
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_DST_INFO, 1);
+   tu_cs_emit(cs, A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format->rb));
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_INFO, 1);
+   tu_cs_emit(cs, A6XX_RB_BLIT_INFO_GMEM | A6XX_RB_BLIT_INFO_CLEAR_MASK(component_mask));
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_BASE_GMEM, 1);
+   tu_cs_emit(cs, cmd->state.pass->attachments[attachment].gmem_offset);
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_UNKNOWN_88D0, 1);
+   tu_cs_emit(cs, 0);
+
+   uint32_t clear_vals[4] = { 0 };
+   tu_pack_clear_value(value, fmt, clear_vals);
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_CLEAR_COLOR_DW0, 4);
+   tu_cs_emit(cs, clear_vals[0]);
+   tu_cs_emit(cs, clear_vals[1]);
+   tu_cs_emit(cs, clear_vals[2]);
+   tu_cs_emit(cs, clear_vals[3]);
+
+   tu6_emit_event_write(cmd, cs, BLIT, false);
+}
+
 void
 tu_CmdClearAttachments(VkCommandBuffer commandBuffer,
                        uint32_t attachmentCount,
@@ -103,17 +171,20 @@ tu_CmdClearAttachments(VkCommandBuffer commandBuffer,
    const struct tu_subpass *subpass = cmd->state.subpass;
    struct tu_cs *cs = &cmd->draw_cs;
 
-   VkResult result = tu_cs_reserve_space(cmd->device, cs,
-                                         rectCount * (3 + 15 * attachmentCount));
+   /* Note: reserving space here should never fail because we allocated
+    * enough above.
+    */
+   struct tu_cond_exec_state state;
+   VkResult result =
+      tu_cond_exec_start(cmd->device, cs, &state,
+                        CP_COND_REG_EXEC_0_MODE(RENDER_MODE) |
+                        CP_COND_REG_EXEC_0_GMEM,
+                        rectCount * (3 + attachmentCount * 15));
    if (result != VK_SUCCESS) {
       cmd->record_result = result;
       return;
    }
 
-   /* TODO: deal with layered rendering (when layered rendering is implemented)
-    * TODO: disable bypass rendering for subpass (when bypass is implemented)
-    */
-
    for (unsigned i = 0; i < rectCount; i++) {
       unsigned x1 = pRects[i].rect.offset.x;
       unsigned y1 = pRects[i].rect.offset.y;
@@ -141,32 +212,54 @@ tu_CmdClearAttachments(VkCommandBuffer commandBuffer,
          if (a == VK_ATTACHMENT_UNUSED)
                continue;
 
-         VkFormat fmt = cmd->state.pass->attachments[a].format;
-         const struct tu_native_format *format = tu6_get_native_format(fmt);
-         assert(format && format->rb >= 0);
+         tu_clear_gmem_attachment(cmd, cs, a, clear_mask,
+                                  &pAttachments[j].clearValue);
 
-         tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_DST_INFO, 1);
-         tu_cs_emit(cs, A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format->rb));
+      }
+   }
+
+   tu_cond_exec_end(cs, &state);
 
-         tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_INFO, 1);
-         tu_cs_emit(cs, A6XX_RB_BLIT_INFO_GMEM | A6XX_RB_BLIT_INFO_CLEAR_MASK(clear_mask));
+   uint32_t clear_count = 3;
+   for (unsigned j = 0; j < rectCount; j++)
+      clear_count += 18 + 66 * pRects[j].layerCount + 17;
 
-         tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_BASE_GMEM, 1);
-         tu_cs_emit(cs, cmd->state.pass->attachments[a].gmem_offset);
+   result =
+      tu_cond_exec_start(cmd->device, cs, &state,
+                         CP_COND_REG_EXEC_0_MODE(RENDER_MODE) |
+                         CP_COND_REG_EXEC_0_SYSMEM,
+                         attachmentCount * clear_count);
 
-         tu_cs_emit_pkt4(cs, REG_A6XX_RB_UNKNOWN_88D0, 1);
-         tu_cs_emit(cs, 0);
+   if (result != VK_SUCCESS) {
+      cmd->record_result = result;
+      return;
+   }
 
-         uint32_t clear_vals[4] = { 0 };
-         tu_pack_clear_value(&pAttachments[j].clearValue, fmt, clear_vals);
+   for (unsigned i = 0; i < rectCount; i++) {
+      for (unsigned j = 0; j < attachmentCount; j++) {
+         uint32_t a;
+         unsigned clear_mask = 0;
+         if (pAttachments[j].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
+            clear_mask = 0xf;
+            a = subpass->color_attachments[pAttachments[j].colorAttachment].attachment;
+         } else {
+            a = subpass->depth_stencil_attachment.attachment;
+            if (pAttachments[j].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
+               clear_mask |= 1;
+            if (pAttachments[j].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
+               clear_mask |= 2;
+            if (clear_mask != 3)
+               tu_finishme("sysmem depth/stencil only clears");
+         }
 
-         tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_CLEAR_COLOR_DW0, 4);
-         tu_cs_emit(cs, clear_vals[0]);
-         tu_cs_emit(cs, clear_vals[1]);
-         tu_cs_emit(cs, clear_vals[2]);
-         tu_cs_emit(cs, clear_vals[3]);
+         if (a == VK_ATTACHMENT_UNUSED)
+               continue;
 
-         tu6_emit_event_write(cmd, cs, BLIT, false);
+         tu_clear_sysmem_attachment(cmd, cs, a,
+                                    &pAttachments[j].clearValue,
+                                    &pRects[i]);
       }
    }
+
+   tu_cond_exec_end(cs, &state);
 }
index a86a18bdfa307f2b8f2ef6e46ef2ff9e239fe85c..7c53e509d8ee065680013aec4291267b82b8cb86 100644 (file)
@@ -1636,6 +1636,21 @@ tu_gem_info_offset(const struct tu_device *dev, uint32_t gem_handle);
 uint64_t
 tu_gem_info_iova(const struct tu_device *dev, uint32_t gem_handle);
 
+
+void
+tu_clear_sysmem_attachment(struct tu_cmd_buffer *cmd,
+                           struct tu_cs *cs,
+                           uint32_t attachment,
+                           const VkClearValue *value,
+                           const VkClearRect *rect);
+
+void
+tu_clear_gmem_attachment(struct tu_cmd_buffer *cmd,
+                         struct tu_cs *cs,
+                         uint32_t attachment,
+                         uint8_t component_mask,
+                         const VkClearValue *value);
+
 #define TU_DEFINE_HANDLE_CASTS(__tu_type, __VkType)                          \
                                                                              \
    static inline struct __tu_type *__tu_type##_from_handle(__VkType _handle) \