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

Author: Mike Blumenkrantz <[email protected]>
Date:   Tue Oct  6 16:07:14 2020 -0400

zink: optimize pipeline hashing

we can reorder the pipeline state and avoid hashing the big arrays based
on context states that we already have available to us

also we can do incremental hashes for the shader modules to further reduce
hashing

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9539>

---

 src/gallium/drivers/zink/zink_context.c  |  2 +
 src/gallium/drivers/zink/zink_draw.c     |  2 +
 src/gallium/drivers/zink/zink_pipeline.h | 14 +++++--
 src/gallium/drivers/zink/zink_program.c  | 65 ++++++++++++++++++++++++++++----
 4 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/src/gallium/drivers/zink/zink_context.c 
b/src/gallium/drivers/zink/zink_context.c
index a570d96c5f7..ac0d587ec1c 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -2104,6 +2104,8 @@ zink_context_create(struct pipe_screen *pscreen, void 
*priv, unsigned flags)
    zink_context_resource_init(&ctx->base);
    zink_context_query_init(&ctx->base);
 
+   ctx->gfx_pipeline_state.have_EXT_extended_dynamic_state = 
screen->info.have_EXT_extended_dynamic_state;
+
    slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);
 
    ctx->base.stream_uploader = u_upload_create_default(&ctx->base);
diff --git a/src/gallium/drivers/zink/zink_draw.c 
b/src/gallium/drivers/zink/zink_draw.c
index 88a43796a8d..8cbf5fbf628 100644
--- a/src/gallium/drivers/zink/zink_draw.c
+++ b/src/gallium/drivers/zink/zink_draw.c
@@ -257,6 +257,8 @@ get_gfx_program(struct zink_context *ctx)
          if (!entry)
             return NULL;
       }
+      if (ctx->curr_program != entry->data)
+         ctx->gfx_pipeline_state.combined_dirty = true;
       ctx->curr_program = entry->data;
       unsigned bits = u_bit_consecutive(PIPE_SHADER_VERTEX, 5);
       ctx->dirty_shader_stages &= ~bits;
diff --git a/src/gallium/drivers/zink/zink_pipeline.h 
b/src/gallium/drivers/zink/zink_pipeline.h
index 0e6daea2514..1f8b62f6a17 100644
--- a/src/gallium/drivers/zink/zink_pipeline.h
+++ b/src/gallium/drivers/zink/zink_pipeline.h
@@ -41,8 +41,6 @@ struct zink_gfx_pipeline_state {
    struct zink_render_pass *render_pass;
 
    struct zink_vertex_elements_hw_state *element_state;
-   VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination 
of element_state and stride
-   VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
    uint8_t divisors_present;
 
    uint32_t num_attachments;
@@ -60,13 +58,21 @@ struct zink_gfx_pipeline_state {
 
    bool primitive_restart;
 
-   VkShaderModule modules[PIPE_SHADER_TYPES - 1];
-
    /* Pre-hashed value for table lookup, invalid when zero.
     * Members after this point are not included in pipeline state hash key */
    uint32_t hash;
    bool dirty;
+
+   VkShaderModule modules[PIPE_SHADER_TYPES - 1];
+   uint32_t module_hash;
+
+   uint32_t combined_hash;
+   bool combined_dirty;
+
+   VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
+   VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination 
of element_state and stride
    uint32_t vertex_buffers_enabled_mask;
+   bool have_EXT_extended_dynamic_state;
 };
 
 struct zink_compute_pipeline_state {
diff --git a/src/gallium/drivers/zink/zink_program.c 
b/src/gallium/drivers/zink/zink_program.c
index 5c84f30ebdb..fe39fd7c3ac 100644
--- a/src/gallium/drivers/zink/zink_program.c
+++ b/src/gallium/drivers/zink/zink_program.c
@@ -37,6 +37,7 @@
 #include "util/u_memory.h"
 #include "tgsi/tgsi_from_mesa.h"
 
+/* for pipeline cache */
 #define XXH_INLINE_ALL
 #include "util/xxhash.h"
 
@@ -351,6 +352,8 @@ update_shader_modules(struct zink_context *ctx, struct 
zink_shader *stages[ZINK_
 {
    struct zink_shader *dirty[ZINK_SHADER_COUNT] = {NULL};
 
+   if (!ctx->dirty_shader_stages)
+      return;
    /* we need to map pipe_shader_type -> gl_shader_stage so we can ensure that 
we're compiling
     * the shaders in pipeline order and have builtin input/output locations 
match up after being compacted
     */
@@ -373,12 +376,15 @@ update_shader_modules(struct zink_context *ctx, struct 
zink_shader *stages[ZINK_
          struct zink_shader_module *zm;
          zm = get_shader_module_for_stage(ctx, dirty[i], prog);
          zink_shader_module_reference(zink_screen(ctx->base.screen), 
&prog->modules[type], zm);
-         /* we probably need a new pipeline when we switch shader modules */
-         ctx->gfx_pipeline_state.dirty = true;
       } else if (stages[type] && !disallow_reuse) /* reuse existing shader 
module */
          zink_shader_module_reference(zink_screen(ctx->base.screen), 
&prog->modules[type], ctx->curr_program->modules[type]);
+      if (ctx->gfx_pipeline_state.modules[type] !=
+          (prog->modules[type] ? prog->modules[type]->shader : VK_NULL_HANDLE))
+         ctx->gfx_pipeline_state.combined_dirty = true;
+      ctx->gfx_pipeline_state.modules[type] = prog->modules[type] ? 
prog->modules[type]->shader : VK_NULL_HANDLE;
       prog->shaders[type] = stages[type];
    }
+   ctx->gfx_pipeline_state.module_hash = 
_mesa_hash_data(ctx->gfx_pipeline_state.modules, 
sizeof(ctx->gfx_pipeline_state.modules));
    unsigned clean = u_bit_consecutive(PIPE_SHADER_VERTEX, 5);;
    ctx->dirty_shader_stages &= ~clean;
 }
@@ -386,13 +392,54 @@ update_shader_modules(struct zink_context *ctx, struct 
zink_shader *stages[ZINK_
 static uint32_t
 hash_gfx_pipeline_state(const void *key)
 {
+   const struct zink_gfx_pipeline_state *state = key;
+   uint32_t hash = 0;
+   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);
+      while (vertex_buffers_enabled_mask) {
+         unsigned idx = u_bit_scan(&vertex_buffers_enabled_mask);
+         hash = XXH32(&state->bindings[idx], 
sizeof(VkVertexInputBindingDescription), hash);
+      }
+   }
+   for (unsigned i = 0; i < state->divisors_present; i++)
+      hash = XXH32(&state->divisors[i], 
sizeof(VkVertexInputBindingDivisorDescriptionEXT), hash);
    return _mesa_hash_data(key, offsetof(struct zink_gfx_pipeline_state, hash));
 }
 
 static bool
 equals_gfx_pipeline_state(const void *a, const void *b)
 {
-   return !memcmp(a, b, offsetof(struct zink_gfx_pipeline_state, hash));
+   const struct zink_gfx_pipeline_state *sa = a;
+   const struct zink_gfx_pipeline_state *sb = b;
+   if (sa->vertex_buffers_enabled_mask != sb->vertex_buffers_enabled_mask)
+      return false;
+   if (!sa->have_EXT_extended_dynamic_state) {
+      /* if we don't have dynamic states, we have to hash the enabled vertex 
buffer bindings */
+      uint32_t mask_a = sa->vertex_buffers_enabled_mask;
+      uint32_t mask_b = sb->vertex_buffers_enabled_mask;
+      while (mask_a || mask_b) {
+         unsigned idx_a = u_bit_scan(&mask_a);
+         unsigned idx_b = u_bit_scan(&mask_b);
+         if (memcmp(&sa->bindings[idx_a], &sb->bindings[idx_b], 
sizeof(VkVertexInputBindingDescription)))
+            return false;
+      }
+   }
+   if (sa->divisors_present != sb->divisors_present)
+      return false;
+   if (sa->divisors_present && sb->divisors_present) {
+      uint32_t divisors_present_a = sa->divisors_present;
+      uint32_t divisors_present_b = sb->divisors_present;
+      while (divisors_present_a || divisors_present_b) {
+         unsigned idx_a = u_bit_scan(&divisors_present_a);
+         unsigned idx_b = u_bit_scan(&divisors_present_b);
+         if (memcmp(&sa->divisors[idx_a], &sb->divisors[idx_b], 
sizeof(VkVertexInputBindingDivisorDescriptionEXT)))
+            return false;
+      }
+   }
+   return !memcmp(sa->modules, sb->modules, sizeof(sa->modules)) &&
+          !memcmp(a, b, offsetof(struct zink_gfx_pipeline_state, hash));
 }
 
 static void
@@ -834,13 +881,15 @@ zink_get_gfx_pipeline(struct zink_screen *screen,
    struct hash_entry *entry = NULL;
    
    if (state->dirty) {
-      for (unsigned i = 0; i < ZINK_SHADER_COUNT; i++)
-         state->modules[i] = prog->modules[i] ? prog->modules[i]->shader : 
VK_NULL_HANDLE;
-
+      state->combined_dirty = true;
       state->hash = hash_gfx_pipeline_state(state);
       state->dirty = false;
    }
-   entry = _mesa_hash_table_search_pre_hashed(prog->pipelines[vkmode], 
state->hash, state);
+   if (state->combined_dirty) {
+      state->combined_hash = XXH32(&state->module_hash, sizeof(uint32_t), 
state->hash);
+      state->combined_dirty = false;
+   }
+   entry = _mesa_hash_table_search_pre_hashed(prog->pipelines[vkmode], 
state->combined_hash, state);
 
    if (!entry) {
       VkPipeline pipeline = zink_create_gfx_pipeline(screen, prog,
@@ -855,7 +904,7 @@ zink_get_gfx_pipeline(struct zink_screen *screen,
       memcpy(&pc_entry->state, state, sizeof(*state));
       pc_entry->pipeline = pipeline;
 
-      entry = _mesa_hash_table_insert_pre_hashed(prog->pipelines[vkmode], 
state->hash, state, pc_entry);
+      entry = _mesa_hash_table_insert_pre_hashed(prog->pipelines[vkmode], 
state->combined_hash, state, pc_entry);
       assert(entry);
    }
 

_______________________________________________
mesa-commit mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-commit

Reply via email to