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