Mesa (main): zink: replace shader module hash table with a list

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Sep 16 04:14:35 UTC 2021


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

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Wed Sep  1 16:46:27 2021 -0400

zink: replace shader module hash table with a list

this should be significantly more performant for the majority of cases
since it's rare that shaders have multiple variants outside of unit tests,
so now there can just be a list of shaders being iterated instead where the
first entry is the last used

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

---

 src/gallium/drivers/zink/zink_program.c | 121 +++++++++++---------------------
 src/gallium/drivers/zink/zink_program.h |  10 ++-
 2 files changed, 45 insertions(+), 86 deletions(-)

diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c
index a90f4a19e83..c956f64d0a4 100644
--- a/src/gallium/drivers/zink/zink_program.c
+++ b/src/gallium/drivers/zink/zink_program.c
@@ -66,53 +66,20 @@ debug_describe_zink_compute_program(char *buf, const struct zink_compute_program
    sprintf(buf, "zink_compute_program");
 }
 
-/* copied from iris */
-struct keybox {
-   uint16_t size;
-   uint8_t data[0];
-};
-
-static struct keybox *
-make_keybox(void *mem_ctx, const void *key, uint32_t key_size, const void *base, uint32_t num_uniforms)
-{
-   unsigned uniform_size = num_uniforms * sizeof(uint32_t); 
-   struct keybox *keybox = ralloc_size(mem_ctx, sizeof(struct keybox) + key_size + uniform_size);
-
-   keybox->size = key_size + uniform_size;
-   memcpy(keybox->data, key, key_size);
-   if (num_uniforms)
-      memcpy(&keybox->data[key_size], base, uniform_size);
-   return keybox;
-}
-
-static uint32_t
-keybox_hash(const void *void_key)
-{
-   const struct keybox *key = void_key;
-   return _mesa_hash_data(&key->data, key->size);
-}
-
 static bool
-keybox_equals(const void *void_a, const void *void_b)
+shader_key_matches(const struct zink_shader_module *zm, const struct zink_shader_key *key, unsigned num_uniforms)
 {
-   const struct keybox *a = void_a, *b = void_b;
-   if (a->size != b->size)
+   if (zm->key_size != key->size || zm->num_uniforms != num_uniforms)
       return false;
-
-   return memcmp(a->data, b->data, a->size) == 0;
+   return !memcmp(zm->key, key, zm->key_size) &&
+          (!num_uniforms || !memcmp(zm->key + zm->key_size, key->base.inlined_uniform_values, zm->num_uniforms * sizeof(uint32_t)));
 }
 
-/* return pointer to make function reusable */
-static inline struct zink_shader_module **
-get_default_shader_module_ptr(struct zink_gfx_program *prog, struct zink_shader *zs, const struct zink_shader_key *key)
+static uint32_t
+shader_module_hash(const struct zink_shader_module *zm)
 {
-   if (zs->nir->info.stage == MESA_SHADER_VERTEX ||
-       zs->nir->info.stage == MESA_SHADER_TESS_EVAL) {
-      /* no streamout or halfz */
-      if (!zink_vs_key_base(key)->last_vertex_stage)
-         return &prog->default_variants[zs->nir->info.stage][1];
-   }
-   return &prog->default_variants[zs->nir->info.stage][0];
+   unsigned key_size = zm->key_size + zm->num_uniforms * sizeof(uint32_t);
+   return _mesa_hash_data(zm->key, key_size);
 }
 
 static struct zink_shader_module *
@@ -123,21 +90,18 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen
    gl_shader_stage stage = zs->nir->info.stage;
    enum pipe_shader_type pstage = pipe_shader_type_from_mesa(stage);
    VkShaderModule mod;
-   struct zink_shader_module *zm;
-   struct zink_shader_module **default_zm = NULL;
-   struct keybox *keybox;
-   uint32_t hash;
+   struct zink_shader_module *zm = NULL;
    unsigned base_size = 0;
    bool is_default_variant;
    const struct zink_shader_key *key = &state->shader_keys.key[pstage];
 
    /* this is default variant if there is no default or it matches the default */
-   if (pstage != PIPE_SHADER_TESS_CTRL && prog->default_variant_key[pstage]) {
-      const struct keybox *tmp = prog->default_variant_key[pstage];
+   if (pstage != PIPE_SHADER_TESS_CTRL && prog->default_variants[pstage]) {
+      const struct zink_shader_module *tmp = prog->default_variants[pstage];
       /* if comparing against the existing default, use the base variant key size since
        * we're only checking the stage-specific data
        */
-      is_default_variant = tmp->size == key->size && !memcmp(tmp->data, &key, key->size);
+      is_default_variant = shader_key_matches(tmp, key, 0);
    } else
       is_default_variant = true;
 
@@ -147,46 +111,43 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen
       is_default_variant = false;
    }
    if (is_default_variant) {
-      default_zm = get_default_shader_module_ptr(prog, zs, key);
-      if (*default_zm)
-         return *default_zm;
+      if (prog->default_variants[pstage])
+         return prog->default_variants[pstage];
+   }
+   struct zink_shader_module *iter, *next;
+   LIST_FOR_EACH_ENTRY_SAFE(iter, next, &prog->shader_cache[pstage], list) {
+      if (!shader_key_matches(iter, key, base_size))
+         continue;
+      list_delinit(&iter->list);
+      zm = iter;
+      break;
    }
-   keybox = make_keybox(prog, key, key->size, &key->base, base_size);
-   hash = keybox_hash(keybox);
-   struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&prog->shader_cache[pstage],
-                                                                 hash, keybox);
-
-   if (entry) {
-      ralloc_free(keybox);
-      zm = entry->data;
-   } else {
-      zm = malloc(sizeof(struct zink_shader_module) + key->size);
+
+   if (!zm) {
+      zm = malloc(sizeof(struct zink_shader_module) + key->size + base_size * sizeof(uint32_t));
       if (!zm) {
-         ralloc_free(keybox);
          return NULL;
       }
-      zm->hash = hash;
-      zm->num_uniforms = base_size;
-      zm->key_size = key->size;
-      if (base_size)
-         memcpy(zm->uniforms, &key->base, base_size * sizeof(uint32_t));
-      memcpy(zm->key, key, key->size);
       mod = zink_shader_compile(screen, zs, prog->nir[stage], key);
       if (!mod) {
-         ralloc_free(keybox);
          FREE(zm);
          return NULL;
       }
       zm->shader = mod;
-
-      _mesa_hash_table_insert_pre_hashed(&prog->shader_cache[pstage], hash, keybox, zm);
+      list_inithead(&zm->list);
+      zm->num_uniforms = base_size;
+      zm->key_size = key->size;
+      memcpy(zm->key, key, key->size);
+      if (base_size)
+         memcpy(zm->key + key->size, &key->base, base_size * sizeof(uint32_t));
+      zm->hash = shader_module_hash(zm);
       if (is_default_variant) {
-         /* previously returned */
-         *default_zm = zm;
+         prog->default_variants[pstage] = zm;
          zm->default_variant = true;
-         prog->default_variant_key[pstage] = keybox;
-      }
+      } else
+         zm->default_variant = false;
    }
+   list_add(&zm->list, &prog->shader_cache[pstage]);
    return zm;
 }
 
@@ -198,10 +159,11 @@ zink_destroy_shader_module(struct zink_screen *screen, struct zink_shader_module
 }
 
 static void
-destroy_shader_cache(struct zink_screen *screen, struct hash_table *sc)
+destroy_shader_cache(struct zink_screen *screen, struct list_head *sc)
 {
-   hash_table_foreach(sc, entry) {
-      struct zink_shader_module *zm = entry->data;
+   struct zink_shader_module *zm, *next;
+   LIST_FOR_EACH_ENTRY_SAFE(zm, next, sc, list) {
+      list_delinit(&zm->list);
       zink_destroy_shader_module(screen, zm);
    }
 }
@@ -376,8 +338,8 @@ zink_create_gfx_program(struct zink_context *ctx,
    pipe_reference_init(&prog->base.reference, 1);
 
    for (int i = 0; i < ZINK_SHADER_COUNT; ++i) {
+      list_inithead(&prog->shader_cache[i]);
       if (stages[i]) {
-         _mesa_hash_table_init(&prog->shader_cache[i], prog, keybox_hash, keybox_equals);
          prog->shaders[i] = stages[i];
          prog->stages_present |= BITFIELD_BIT(i);
       }
@@ -386,7 +348,6 @@ zink_create_gfx_program(struct zink_context *ctx,
       prog->shaders[PIPE_SHADER_TESS_EVAL]->generated =
       prog->shaders[PIPE_SHADER_TESS_CTRL] =
         zink_shader_tcs_create(screen, stages[PIPE_SHADER_VERTEX], vertices_per_patch);
-        _mesa_hash_table_init(&prog->shader_cache[PIPE_SHADER_TESS_CTRL], prog, keybox_hash, keybox_equals);
       prog->stages_present |= BITFIELD_BIT(PIPE_SHADER_TESS_CTRL);
    }
 
diff --git a/src/gallium/drivers/zink/zink_program.h b/src/gallium/drivers/zink/zink_program.h
index 52c28c64330..f7efd1e27cb 100644
--- a/src/gallium/drivers/zink/zink_program.h
+++ b/src/gallium/drivers/zink/zink_program.h
@@ -64,13 +64,13 @@ struct zink_cs_push_constant {
  * allowing us to skip going through shader keys
  */
 struct zink_shader_module {
+   struct list_head list;
    VkShaderModule shader;
    uint32_t hash;
    bool default_variant;
    uint8_t num_uniforms;
    uint8_t key_size;
-   uint32_t uniforms[MAX_INLINABLE_UNIFORMS];
-   uint8_t key[0];
+   uint8_t key[0]; /* | key | uniforms | */
 };
 
 struct zink_program {
@@ -99,12 +99,10 @@ struct zink_gfx_program {
 
    struct zink_shader_module *modules[ZINK_SHADER_COUNT]; // compute stage doesn't belong here
 
-   struct zink_shader_module *default_variants[ZINK_SHADER_COUNT][2]; //[default, no streamout]
-   const void *default_variant_key[ZINK_SHADER_COUNT];
+   struct zink_shader_module *default_variants[ZINK_SHADER_COUNT];
    struct zink_shader *last_vertex_stage;
 
-   /* the shader cache stores a mapping of zink_shader_key::VkShaderModule */
-   struct hash_table shader_cache[ZINK_SHADER_COUNT];
+   struct list_head shader_cache[ZINK_SHADER_COUNT];
 
    struct zink_shader *shaders[ZINK_SHADER_COUNT];
    struct hash_table pipelines[11]; // number of draw modes we support



More information about the mesa-commit mailing list