Mesa (master): turnip: rework vertex buffers draw state handling

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Sep 10 13:54:17 UTC 2020


Module: Mesa
Branch: master
Commit: 52becd39a590cc8cac7bbe38282b27fc0a8ebbbf
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=52becd39a590cc8cac7bbe38282b27fc0a8ebbbf

Author: Jonathan Marek <jonathan at marek.ca>
Date:   Wed Sep  9 09:26:59 2020 -0400

turnip: rework vertex buffers draw state handling

This exploits a HW optimization for when only the size of a draw state is
changed, to make things simpler and more optimal (assuming a well behaved
user which doesn't unecessarily call CmdBindVertexBuffers many times)

Signed-off-by: Jonathan Marek <jonathan at marek.ca>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6665>

---

 src/freedreno/vulkan/tu_cmd_buffer.c | 66 +++++++++++++-----------------------
 src/freedreno/vulkan/tu_pipeline.c   | 14 +++-----
 src/freedreno/vulkan/tu_private.h    | 21 ++++--------
 3 files changed, 35 insertions(+), 66 deletions(-)

diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c
index 2e144d10e14..447a438af4d 100644
--- a/src/freedreno/vulkan/tu_cmd_buffer.c
+++ b/src/freedreno/vulkan/tu_cmd_buffer.c
@@ -1638,10 +1638,6 @@ tu_BeginCommandBuffer(VkCommandBuffer commandBuffer,
    return VK_SUCCESS;
 }
 
-/* Sets vertex buffers to HW binding points.  We emit VBs in SDS (so that bin
- * rendering can skip over unused state), so we need to collect all the
- * bindings together into a single state emit at draw time.
- */
 void
 tu_CmdBindVertexBuffers(VkCommandBuffer commandBuffer,
                         uint32_t firstBinding,
@@ -1650,18 +1646,25 @@ tu_CmdBindVertexBuffers(VkCommandBuffer commandBuffer,
                         const VkDeviceSize *pOffsets)
 {
    TU_FROM_HANDLE(tu_cmd_buffer, cmd, commandBuffer);
-
-   assert(firstBinding + bindingCount <= MAX_VBS);
+   struct tu_cs cs;
+   /* TODO: track a "max_vb" value for the cmdbuf to save a bit of memory  */
+   cmd->state.vertex_buffers.iova = tu_cs_draw_state(&cmd->sub_cs, &cs, 4 * MAX_VBS).iova;
 
    for (uint32_t i = 0; i < bindingCount; i++) {
       struct tu_buffer *buf = tu_buffer_from_handle(pBuffers[i]);
 
-      cmd->state.vb.buffers[firstBinding + i] = buf;
-      cmd->state.vb.offsets[firstBinding + i] = pOffsets[i];
-
+      cmd->state.vb[firstBinding + i].base = tu_buffer_iova(buf) + pOffsets[i];
+      cmd->state.vb[firstBinding + i].size = buf->size - pOffsets[i];
       tu_bo_list_add(&cmd->bo_list, buf->bo, MSM_SUBMIT_BO_READ);
    }
 
+   for (uint32_t i = 0; i < MAX_VBS; i++) {
+      tu_cs_emit_regs(&cs,
+                      A6XX_VFD_FETCH_BASE_LO(i, cmd->state.vb[i].base),
+                      A6XX_VFD_FETCH_BASE_HI(i, cmd->state.vb[i].base >> 32),
+                      A6XX_VFD_FETCH_SIZE(i, cmd->state.vb[i].size));
+   }
+
    cmd->state.dirty |= TU_CMD_DIRTY_VERTEX_BUFFERS;
 }
 
@@ -2114,13 +2117,6 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer,
    for_each_bit(i, mask)
       tu_cs_emit_draw_state(cs, TU_DRAW_STATE_DYNAMIC + i, pipeline->dynamic_state[i]);
 
-   /* If the new pipeline requires more VBs than we had previously set up, we
-    * need to re-emit them in SDS.  If it requires the same set or fewer, we
-    * can just re-use the old SDS.
-    */
-   if (pipeline->vi.bindings_used & ~cmd->vertex_bindings_set)
-      cmd->state.dirty |= TU_CMD_DIRTY_VERTEX_BUFFERS;
-
    /* dynamic linewidth state depends pipeline state's gras_su_cntl
     * so the dynamic state ib must be updated when pipeline changes
     */
@@ -2132,6 +2128,17 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer,
 
       tu_cs_emit_regs(&cs, A6XX_GRAS_SU_CNTL(.dword = cmd->state.dynamic_gras_su_cntl));
    }
+
+   /* the vertex_buffers draw state always contains all the currently
+    * bound vertex buffers. update its size to only emit the vbs which
+    * are actually used by the pipeline
+    * note there is a HW optimization which makes it so the draw state
+    * is not re-executed completely when only the size changes
+    */
+   if (cmd->state.vertex_buffers.size != pipeline->num_vbs * 4) {
+      cmd->state.vertex_buffers.size = pipeline->num_vbs * 4;
+      cmd->state.dirty |= TU_CMD_DIRTY_VERTEX_BUFFERS;
+   }
 }
 
 void
@@ -2905,30 +2912,6 @@ tu6_emit_consts(struct tu_cmd_buffer *cmd,
    return tu_cs_end_draw_state(&cmd->sub_cs, &cs);
 }
 
-static struct tu_draw_state
-tu6_emit_vertex_buffers(struct tu_cmd_buffer *cmd,
-                        const struct tu_pipeline *pipeline)
-{
-   struct tu_cs cs;
-   tu_cs_begin_sub_stream(&cmd->sub_cs, 4 * MAX_VBS, &cs);
-
-   int binding;
-   for_each_bit(binding, pipeline->vi.bindings_used) {
-      const struct tu_buffer *buf = cmd->state.vb.buffers[binding];
-      const VkDeviceSize offset = buf->bo_offset +
-         cmd->state.vb.offsets[binding];
-
-      tu_cs_emit_regs(&cs,
-                      A6XX_VFD_FETCH_BASE(binding, .bo = buf->bo, .bo_offset = offset),
-                      A6XX_VFD_FETCH_SIZE(binding, buf->size - offset));
-
-   }
-
-   cmd->vertex_bindings_set = pipeline->vi.bindings_used;
-
-   return tu_cs_end_draw_state(&cmd->sub_cs, &cs);
-}
-
 static uint64_t
 get_tess_param_bo_size(const struct tu_pipeline *pipeline,
                        uint32_t draw_count)
@@ -3068,9 +3051,6 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
          tu6_emit_consts(cmd, pipeline, descriptors_state, MESA_SHADER_FRAGMENT);
    }
 
-   if (cmd->state.dirty & TU_CMD_DIRTY_VERTEX_BUFFERS)
-      cmd->state.vertex_buffers = tu6_emit_vertex_buffers(cmd, pipeline);
-
    bool has_tess =
          pipeline->active_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
    struct tu_draw_state tess_consts = {};
diff --git a/src/freedreno/vulkan/tu_pipeline.c b/src/freedreno/vulkan/tu_pipeline.c
index 36c29879b73..4b2be417576 100644
--- a/src/freedreno/vulkan/tu_pipeline.c
+++ b/src/freedreno/vulkan/tu_pipeline.c
@@ -1475,8 +1475,7 @@ tu6_emit_program(struct tu_cs *cs,
 static void
 tu6_emit_vertex_input(struct tu_cs *cs,
                       const struct ir3_shader_variant *vs,
-                      const VkPipelineVertexInputStateCreateInfo *info,
-                      uint32_t *bindings_used)
+                      const VkPipelineVertexInputStateCreateInfo *info)
 {
    uint32_t vfd_decode_idx = 0;
    uint32_t binding_instanced = 0; /* bitmask of instanced bindings */
@@ -1492,7 +1491,6 @@ tu6_emit_vertex_input(struct tu_cs *cs,
       if (binding->inputRate == VK_VERTEX_INPUT_RATE_INSTANCE)
          binding_instanced |= 1 << binding->binding;
 
-      *bindings_used |= 1 << binding->binding;
       step_rate[binding->binding] = 1;
    }
 
@@ -1513,8 +1511,6 @@ tu6_emit_vertex_input(struct tu_cs *cs,
          &info->pVertexAttributeDescriptions[i];
       uint32_t input_idx;
 
-      assert(*bindings_used & BIT(attr->binding));
-
       for (input_idx = 0; input_idx < vs->inputs_count; input_idx++) {
          if ((vs->inputs[input_idx].slot - VERT_ATTRIB_GENERIC0) == attr->location)
             break;
@@ -2173,18 +2169,18 @@ tu_pipeline_builder_parse_vertex_input(struct tu_pipeline_builder *builder,
    const struct ir3_shader_variant *vs = builder->variants[MESA_SHADER_VERTEX];
    const struct ir3_shader_variant *bs = builder->binning_variant;
 
+   pipeline->num_vbs = vi_info->vertexBindingDescriptionCount;
+
    struct tu_cs vi_cs;
    tu_cs_begin_sub_stream(&pipeline->cs,
                           MAX_VERTEX_ATTRIBS * 7 + 2, &vi_cs);
-   tu6_emit_vertex_input(&vi_cs, vs, vi_info,
-                         &pipeline->vi.bindings_used);
+   tu6_emit_vertex_input(&vi_cs, vs, vi_info);
    pipeline->vi.state = tu_cs_end_draw_state(&pipeline->cs, &vi_cs);
 
    if (bs) {
       tu_cs_begin_sub_stream(&pipeline->cs,
                              MAX_VERTEX_ATTRIBS * 7 + 2, &vi_cs);
-      tu6_emit_vertex_input(
-         &vi_cs, bs, vi_info, &pipeline->vi.bindings_used);
+      tu6_emit_vertex_input(&vi_cs, bs, vi_info);
       pipeline->vi.binning_state =
          tu_cs_end_draw_state(&pipeline->cs, &vi_cs);
    }
diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h
index 439a08d7cd2..0a70b58fbdc 100644
--- a/src/freedreno/vulkan/tu_private.h
+++ b/src/freedreno/vulkan/tu_private.h
@@ -676,12 +676,6 @@ tu_buffer_iova(struct tu_buffer *buffer)
    return buffer->bo->iova + buffer->bo_offset;
 }
 
-struct tu_vertex_binding
-{
-   struct tu_buffer *buffer;
-   VkDeviceSize offset;
-};
-
 const char *
 tu_get_debug_option_name(int id);
 
@@ -861,11 +855,10 @@ struct tu_cmd_state
    struct tu_pipeline *compute_pipeline;
 
    /* Vertex buffers */
-   struct
-   {
-      struct tu_buffer *buffers[MAX_VBS];
-      VkDeviceSize offsets[MAX_VBS];
-   } vb;
+   struct {
+      uint64_t base;
+      uint32_t size;
+   } vb[MAX_VBS];
 
    /* for dynamic states that can't be emitted directly */
    uint32_t dynamic_stencil_mask;
@@ -983,8 +976,6 @@ struct tu_cmd_buffer
    enum tu_cmd_buffer_status status;
 
    struct tu_cmd_state state;
-   struct tu_vertex_binding vertex_bindings[MAX_VBS];
-   uint32_t vertex_bindings_set;
    uint32_t queue_family_index;
 
    uint32_t push_constants[MAX_PUSH_CONSTANTS_SIZE / 4];
@@ -1115,6 +1106,9 @@ struct tu_pipeline
    /* draw states for the pipeline */
    struct tu_draw_state load_state, rast_state, ds_state, blend_state;
 
+   /* for vertex buffers state */
+   uint32_t num_vbs;
+
    struct
    {
       struct tu_draw_state state;
@@ -1127,7 +1121,6 @@ struct tu_pipeline
    {
       struct tu_draw_state state;
       struct tu_draw_state binning_state;
-      uint32_t bindings_used;
    } vi;
 
    struct



More information about the mesa-commit mailing list