Mesa (main): zink: EXT_vertex_input_dynamic_state

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jul 27 00:49:07 UTC 2021


Module: Mesa
Branch: main
Commit: 6691a48bcc617bd8ec3ba248a4fa79ceb25e86e3
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=6691a48bcc617bd8ec3ba248a4fa79ceb25e86e3

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Thu May 13 15:55:43 2021 -0400

zink: EXT_vertex_input_dynamic_state

this eliminates vertex attributes from the pipeline state, massively
deduplicating the number of pipelines needed

Reviewed-by: Dave Airlie <airlied at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12009>

---

 src/gallium/drivers/zink/zink_context.c      |  4 +--
 src/gallium/drivers/zink/zink_context.h      |  1 +
 src/gallium/drivers/zink/zink_device_info.py |  4 +++
 src/gallium/drivers/zink/zink_draw.cpp       | 13 +++++++-
 src/gallium/drivers/zink/zink_pipeline.c     | 32 +++++++++++-------
 src/gallium/drivers/zink/zink_pipeline.h     |  1 -
 src/gallium/drivers/zink/zink_program.c      | 44 ++++++++++++++----------
 src/gallium/drivers/zink/zink_state.c        | 50 ++++++++++++++++++++--------
 src/gallium/drivers/zink/zink_state.h        | 16 ++++++---
 9 files changed, 113 insertions(+), 52 deletions(-)

diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index 18edf0e7da2..4e5734787d1 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -945,7 +945,7 @@ zink_set_vertex_buffers(struct pipe_context *pctx,
 
    if (buffers) {
       if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
-         ctx->gfx_pipeline_state.vertex_state_dirty = true;
+         ctx->vertex_state_changed = true;
       for (unsigned i = 0; i < num_buffers; ++i) {
          const struct pipe_vertex_buffer *vb = buffers + i;
          struct pipe_vertex_buffer *ctx_vb = &ctx->vertex_buffers[start_slot + i];
@@ -971,7 +971,7 @@ zink_set_vertex_buffers(struct pipe_context *pctx,
       }
    } else {
       if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
-         ctx->gfx_pipeline_state.vertex_state_dirty = true;
+         ctx->vertex_state_changed = true;
       for (unsigned i = 0; i < num_buffers; ++i) {
          update_existing_vbo(ctx, start_slot + i);
          pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);
diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h
index 79499c6c03c..f4ebce713e6 100644
--- a/src/gallium/drivers/zink/zink_context.h
+++ b/src/gallium/drivers/zink/zink_context.h
@@ -303,6 +303,7 @@ struct zink_context {
    bool have_timelines;
 
    bool is_device_lost;
+   bool vertex_state_changed : 1;
    bool blend_state_changed : 1;
    bool rast_state_changed : 1;
    bool dsa_state_changed : 1;
diff --git a/src/gallium/drivers/zink/zink_device_info.py b/src/gallium/drivers/zink/zink_device_info.py
index 205e2d6d7f6..133dfd94b3e 100644
--- a/src/gallium/drivers/zink/zink_device_info.py
+++ b/src/gallium/drivers/zink/zink_device_info.py
@@ -176,6 +176,10 @@ EXTENSIONS = [
         alias="line_rast",
         properties=True,
         features=True),
+    Extension("VK_EXT_vertex_input_dynamic_state",
+        alias="vertex_input",
+	features=True,
+	conditions=["$feats.vertexInputDynamicState"]),
     Extension("VK_KHR_dedicated_allocation",
         alias="dedicated"),
 ]
diff --git a/src/gallium/drivers/zink/zink_draw.cpp b/src/gallium/drivers/zink/zink_draw.cpp
index c06e25d92f8..13d948e9e37 100644
--- a/src/gallium/drivers/zink/zink_draw.cpp
+++ b/src/gallium/drivers/zink/zink_draw.cpp
@@ -130,7 +130,7 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
    VkBuffer buffers[PIPE_MAX_ATTRIBS];
    VkDeviceSize buffer_offsets[PIPE_MAX_ATTRIBS];
    VkDeviceSize buffer_strides[PIPE_MAX_ATTRIBS];
-   const struct zink_vertex_elements_state *elems = ctx->element_state;
+   struct zink_vertex_elements_state *elems = ctx->element_state;
    struct zink_screen *screen = zink_screen(ctx->base.screen);
 
    if (!elems->hw_state.num_bindings)
@@ -143,12 +143,16 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
       if (vb->buffer.resource) {
          buffers[i] = ctx->vbufs[buffer_id];
          assert(buffers[i]);
+         if (screen->info.have_EXT_vertex_input_dynamic_state)
+            elems->hw_state.dynbindings[i].stride = vb->stride;
          buffer_offsets[i] = ctx->vbuf_offsets[buffer_id];
          buffer_strides[i] = vb->stride;
       } else {
          buffers[i] = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;
          buffer_offsets[i] = 0;
          buffer_strides[i] = 0;
+         if (screen->info.have_EXT_vertex_input_dynamic_state)
+            elems->hw_state.dynbindings[i].stride = 0;
       }
    }
 
@@ -160,6 +164,13 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
       vkCmdBindVertexBuffers(batch->state->cmdbuf, 0,
                              elems->hw_state.num_bindings,
                              buffers, buffer_offsets);
+
+   if (screen->info.have_EXT_vertex_input_dynamic_state)
+      screen->vk.CmdSetVertexInputEXT(batch->state->cmdbuf,
+                                      elems->hw_state.num_bindings, elems->hw_state.dynbindings,
+                                      elems->hw_state.num_attribs, elems->hw_state.dynattribs);
+
+   ctx->vertex_state_changed = false;
    ctx->vertex_buffers_dirty = false;
 }
 
diff --git a/src/gallium/drivers/zink/zink_pipeline.c b/src/gallium/drivers/zink/zink_pipeline.c
index 7f5763d28a5..26167b0f06d 100644
--- a/src/gallium/drivers/zink/zink_pipeline.c
+++ b/src/gallium/drivers/zink/zink_pipeline.c
@@ -51,19 +51,23 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
                          struct zink_gfx_pipeline_state *state,
                          VkPrimitiveTopology primitive_topology)
 {
-   VkPipelineVertexInputStateCreateInfo vertex_input_state = {0};
-   vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-   vertex_input_state.pVertexBindingDescriptions = state->element_state->bindings;
-   vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings;
-   vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs;
-   vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs;
-
-   VkPipelineVertexInputDivisorStateCreateInfoEXT vdiv_state = {0};
-   if (state->element_state->divisors_present) {
+   VkPipelineVertexInputStateCreateInfo vertex_input_state;
+   if (!screen->info.have_EXT_vertex_input_dynamic_state) {
+      memset(&vertex_input_state, 0, sizeof(vertex_input_state));
+      vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+      vertex_input_state.pVertexBindingDescriptions = state->element_state->b.bindings;
+      vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings;
+      vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs;
+      vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs;
+   }
+
+   VkPipelineVertexInputDivisorStateCreateInfoEXT vdiv_state;
+   if (!screen->info.have_EXT_vertex_input_dynamic_state && state->element_state->b.divisors_present) {
+       memset(&vdiv_state, 0, sizeof(vdiv_state));
        vertex_input_state.pNext = &vdiv_state;
        vdiv_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
-       vdiv_state.vertexBindingDivisorCount = state->element_state->divisors_present;
-       vdiv_state.pVertexBindingDivisors = state->element_state->divisors;
+       vdiv_state.vertexBindingDivisorCount = state->element_state->b.divisors_present;
+       vdiv_state.pVertexBindingDivisors = state->element_state->b.divisors;
    }
 
    VkPipelineInputAssemblyStateCreateInfo primitive_state = {0};
@@ -202,6 +206,9 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
       dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VIEWPORT;
       dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_SCISSOR;
    }
+   if (screen->info.have_EXT_vertex_input_dynamic_state) {
+      dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT;
+   }
 
    VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {0};
    pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
@@ -212,7 +219,8 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
    pci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    pci.layout = prog->base.layout;
    pci.renderPass = state->render_pass->render_pass;
-   pci.pVertexInputState = &vertex_input_state;
+   if (!screen->info.have_EXT_vertex_input_dynamic_state)
+      pci.pVertexInputState = &vertex_input_state;
    pci.pInputAssemblyState = &primitive_state;
    pci.pRasterizationState = &rast_state;
    pci.pColorBlendState = &blend_state;
diff --git a/src/gallium/drivers/zink/zink_pipeline.h b/src/gallium/drivers/zink/zink_pipeline.h
index 2a171a2163e..69464808027 100644
--- a/src/gallium/drivers/zink/zink_pipeline.h
+++ b/src/gallium/drivers/zink/zink_pipeline.h
@@ -69,7 +69,6 @@ struct zink_gfx_pipeline_state {
    bool combined_dirty;
 
    struct zink_vertex_elements_hw_state *element_state;
-   bool vertex_state_dirty;
 
    uint32_t final_hash;
 
diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c
index eee98b493ca..de3f1eaacc9 100644
--- a/src/gallium/drivers/zink/zink_program.c
+++ b/src/gallium/drivers/zink/zink_program.c
@@ -764,41 +764,49 @@ zink_get_gfx_pipeline(struct zink_context *ctx,
                       struct zink_gfx_pipeline_state *state,
                       enum pipe_prim_type mode)
 {
-   if (!state->dirty && !state->combined_dirty && !state->vertex_state_dirty && mode == state->mode)
+   struct zink_screen *screen = zink_screen(ctx->base.screen);
+   const bool have_EXT_vertex_input_dynamic_state = screen->info.have_EXT_vertex_input_dynamic_state;
+   if (!state->dirty && !state->combined_dirty && mode == state->mode &&
+       (have_EXT_vertex_input_dynamic_state || !ctx->vertex_state_changed))
       return state->pipeline;
 
-   struct zink_screen *screen = zink_screen(ctx->base.screen);
    VkPrimitiveTopology vkmode = primitive_topology(mode);
    assert(vkmode <= ARRAY_SIZE(prog->pipelines));
 
    struct hash_entry *entry = NULL;
 
    if (state->dirty) {
-      state->vertex_state_dirty = state->combined_dirty = true;
+      if (!have_EXT_vertex_input_dynamic_state)
+         ctx->vertex_state_changed = true;
+      state->combined_dirty = true;
       state->hash = hash_gfx_pipeline_state(state);
       state->dirty = false;
    }
    if (state->combined_dirty) {
-      state->vertex_state_dirty = true;
+      if (!have_EXT_vertex_input_dynamic_state)
+         ctx->vertex_state_changed = true;
       state->combined_hash = XXH32(&state->module_hash, sizeof(uint32_t), state->hash);
       state->combined_dirty = false;
    }
-   if (state->vertex_state_dirty) {
-      uint32_t hash = state->combined_hash;
-      if (!state->have_EXT_extended_dynamic_state) {
-         /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
-         uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
-         hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
-
-         for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
-            struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
-            state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
-            hash = XXH32(&state->vertex_strides[i], sizeof(uint32_t), hash);
+   if (have_EXT_vertex_input_dynamic_state)
+      state->final_hash = state->combined_hash;
+   else
+      if (ctx->vertex_state_changed) {
+         uint32_t hash = state->combined_hash;
+         if (!state->have_EXT_extended_dynamic_state) {
+            /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
+            uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
+            hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
+
+            for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
+               struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
+               state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
+               hash = XXH32(&state->vertex_strides[i], sizeof(uint32_t), hash);
+            }
          }
+         state->final_hash = XXH32(&state->element_state, sizeof(void*), hash);
+         ctx->vertex_state_changed = false;
       }
-      state->final_hash = XXH32(&state->element_state, sizeof(void*), hash);
-      state->vertex_state_dirty = false;
-   }
    entry = _mesa_hash_table_search_pre_hashed(prog->pipelines[vkmode], state->final_hash, state);
 
    if (!entry) {
diff --git a/src/gallium/drivers/zink/zink_state.c b/src/gallium/drivers/zink/zink_state.c
index 95453cb3c8a..cf8a1ce7643 100644
--- a/src/gallium/drivers/zink/zink_state.c
+++ b/src/gallium/drivers/zink/zink_state.c
@@ -66,23 +66,45 @@ zink_create_vertex_elements_state(struct pipe_context *pctx,
       ves->divisor[binding] = elem->instance_divisor;
       assert(elem->instance_divisor <= screen->info.vdiv_props.maxVertexAttribDivisor);
 
-      ves->hw_state.attribs[i].binding = binding;
-      ves->hw_state.attribs[i].location = i;
-      ves->hw_state.attribs[i].format = zink_get_format(screen,
-                                                        elem->src_format);
-      assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
-      ves->hw_state.attribs[i].offset = elem->src_offset;
+      if (screen->info.have_EXT_vertex_input_dynamic_state) {
+         ves->hw_state.dynattribs[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT;
+         ves->hw_state.dynattribs[i].binding = binding;
+         ves->hw_state.dynattribs[i].location = i;
+         ves->hw_state.dynattribs[i].format = zink_get_format(screen,
+                                                           elem->src_format);
+         assert(ves->hw_state.dynattribs[i].format != VK_FORMAT_UNDEFINED);
+         ves->hw_state.dynattribs[i].offset = elem->src_offset;
+      } else {
+         ves->hw_state.attribs[i].binding = binding;
+         ves->hw_state.attribs[i].location = i;
+         ves->hw_state.attribs[i].format = zink_get_format(screen,
+                                                           elem->src_format);
+         assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
+         ves->hw_state.attribs[i].offset = elem->src_offset;
+      }
    }
 
    ves->hw_state.num_bindings = num_bindings;
    ves->hw_state.num_attribs = num_elements;
-   for (int i = 0; i < num_bindings; ++i) {
-      ves->hw_state.bindings[i].binding = ves->bindings[i].binding;
-      ves->hw_state.bindings[i].inputRate = ves->bindings[i].inputRate;
-      if (ves->divisor[i]) {
-         ves->hw_state.divisors[ves->hw_state.divisors_present].divisor = ves->divisor[i];
-         ves->hw_state.divisors[ves->hw_state.divisors_present].binding = ves->bindings[i].binding;
-         ves->hw_state.divisors_present++;
+   if (screen->info.have_EXT_vertex_input_dynamic_state) {
+      for (int i = 0; i < num_bindings; ++i) {
+         ves->hw_state.dynbindings[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
+         ves->hw_state.dynbindings[i].binding = ves->bindings[i].binding;
+         ves->hw_state.dynbindings[i].inputRate = ves->bindings[i].inputRate;
+         if (ves->divisor[i])
+            ves->hw_state.dynbindings[i].divisor = ves->divisor[i];
+         else
+            ves->hw_state.dynbindings[i].divisor = 1;
+      }
+   } else {
+      for (int i = 0; i < num_bindings; ++i) {
+         ves->hw_state.b.bindings[i].binding = ves->bindings[i].binding;
+         ves->hw_state.b.bindings[i].inputRate = ves->bindings[i].inputRate;
+         if (ves->divisor[i]) {
+            ves->hw_state.b.divisors[ves->hw_state.b.divisors_present].divisor = ves->divisor[i];
+            ves->hw_state.b.divisors[ves->hw_state.b.divisors_present].binding = ves->bindings[i].binding;
+            ves->hw_state.b.divisors_present++;
+         }
       }
    }
    return ves;
@@ -97,7 +119,7 @@ zink_bind_vertex_elements_state(struct pipe_context *pctx,
    ctx->element_state = cso;
    if (cso) {
       if (state->element_state != &ctx->element_state->hw_state) {
-         state->vertex_state_dirty = true;
+         ctx->vertex_state_changed = true;
          ctx->vertex_buffers_dirty = ctx->element_state->hw_state.num_bindings > 0;
       }
       state->element_state = &ctx->element_state->hw_state;
diff --git a/src/gallium/drivers/zink/zink_state.h b/src/gallium/drivers/zink/zink_state.h
index c333afcd9ad..e314a9bed23 100644
--- a/src/gallium/drivers/zink/zink_state.h
+++ b/src/gallium/drivers/zink/zink_state.h
@@ -29,11 +29,19 @@
 #include "pipe/p_state.h"
 
 struct zink_vertex_elements_hw_state {
-   VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
-   VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
-   VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination of element_state and stride
+   union {
+      VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
+      VkVertexInputAttributeDescription2EXT dynattribs[PIPE_MAX_ATTRIBS];
+   };
+   union {
+      struct {
+         VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
+         VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination of element_state and stride
+         uint8_t divisors_present;
+      } b;
+      VkVertexInputBindingDescription2EXT dynbindings[PIPE_MAX_ATTRIBS];
+   };
    uint32_t num_bindings, num_attribs;
-   uint8_t divisors_present;
 };
 
 struct zink_vertex_elements_state {



More information about the mesa-commit mailing list