From 2be2a500a396fe1dc0e121816e4056874cdd43fc Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Mon, 13 Jul 2020 13:47:19 -0400 Subject: [PATCH] zink: initial implementation of shader keys these are cached per-program for now since we have to ensure that the slot map always matches up between shader states Reviewed-by: Erik Faye-Lund Part-of: --- src/gallium/drivers/zink/zink_compiler.c | 3 +- src/gallium/drivers/zink/zink_compiler.h | 4 +- src/gallium/drivers/zink/zink_program.c | 132 +++++++++++++++++++++++++++++-- src/gallium/drivers/zink/zink_program.h | 14 ++++ src/gallium/drivers/zink/zink_screen.h | 2 + 5 files changed, 148 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index bd35160..dc3c829 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -217,7 +217,7 @@ update_so_info(struct zink_shader *sh, } VkShaderModule -zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, +zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, struct zink_shader_key *key, unsigned char *shader_slot_map, unsigned char *shader_slots_reserved) { VkShaderModule mod = VK_NULL_HANDLE; @@ -260,6 +260,7 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, struct zink_shader *ret = CALLOC_STRUCT(zink_shader); bool have_psiz = false; + ret->shader_id = p_atomic_inc_return(&screen->shader_id); ret->programs = _mesa_pointer_set_create(NULL); /* only do uniforms -> ubo if we have uniforms, otherwise we're just diff --git a/src/gallium/drivers/zink/zink_compiler.h b/src/gallium/drivers/zink/zink_compiler.h index 7ea485f..07a31f5 100644 --- a/src/gallium/drivers/zink/zink_compiler.h +++ b/src/gallium/drivers/zink/zink_compiler.h @@ -35,6 +35,7 @@ struct pipe_screen; struct zink_context; struct zink_screen; +struct zink_shader_key; struct zink_gfx_program; struct nir_shader_compiler_options; @@ -58,6 +59,7 @@ struct nir_shader * zink_tgsi_to_nir(struct pipe_screen *screen, const struct tgsi_token *tokens); struct zink_shader { + unsigned shader_id; struct nir_shader *nir; struct zink_so_info streamout; @@ -74,7 +76,7 @@ struct zink_shader { }; VkShaderModule -zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, +zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, struct zink_shader_key *key, unsigned char *shader_slot_map, unsigned char *shader_slots_reserved); struct zink_shader * diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 31db137..6c047a2 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -27,6 +27,7 @@ #include "zink_context.h" #include "zink_render_pass.h" #include "zink_screen.h" +#include "zink_state.h" #include "util/hash_table.h" #include "util/set.h" @@ -51,6 +52,58 @@ debug_describe_zink_shader_module(char *buf, const struct zink_shader_module *pt sprintf(buf, "zink_shader_module"); } +/* copied from iris */ +struct keybox { + uint16_t size; + gl_shader_stage stage; + uint8_t data[0]; +}; + +static struct keybox * +make_keybox(void *mem_ctx, + gl_shader_stage stage, + const void *key, + uint32_t key_size) +{ + struct keybox *keybox = + ralloc_size(mem_ctx, sizeof(struct keybox) + key_size); + + keybox->stage = stage; + keybox->size = key_size; + memcpy(keybox->data, key, key_size); + + return keybox; +} + +static uint32_t +keybox_hash(const void *void_key) +{ + const struct keybox *key = void_key; + return _mesa_hash_data(&key->stage, key->size + sizeof(key->stage)); +} + +static bool +keybox_equals(const void *void_a, const void *void_b) +{ + const struct keybox *a = void_a, *b = void_b; + if (a->size != b->size) + return false; + + return memcmp(a->data, b->data, a->size) == 0; +} + +static struct zink_shader_module * +find_cached_shader(struct zink_gfx_program *prog, gl_shader_stage stage, uint32_t key_size, const void *key) +{ + struct keybox *keybox = make_keybox(NULL, stage, key, key_size); + struct hash_entry *entry = + _mesa_hash_table_search(prog->shader_cache, keybox); + + ralloc_free(keybox); + + return entry ? entry->data : NULL; +} + static VkDescriptorSetLayout create_desc_set_layout(VkDevice dev, struct zink_shader *stages[ZINK_SHADER_COUNT], @@ -113,6 +166,70 @@ create_pipeline_layout(VkDevice dev, VkDescriptorSetLayout dsl) return layout; } + +static void +shader_key_fs_gen(struct zink_context *ctx, struct zink_shader *zs, struct zink_shader_key *key) +{ + struct zink_fs_key *fs_key = &key->key.fs; + key->size = sizeof(struct zink_fs_key); + + fs_key->shader_id = zs->shader_id; + //fs_key->flat_shade = ctx->rast_state->base.flatshade; +} + +typedef void (*zink_shader_key_gen)(struct zink_context *ctx, struct zink_shader *zs, struct zink_shader_key *key); +static zink_shader_key_gen shader_key_vtbl[] = +{ + [MESA_SHADER_VERTEX] = NULL, + [MESA_SHADER_TESS_CTRL] = NULL, + [MESA_SHADER_TESS_EVAL] = NULL, + [MESA_SHADER_GEOMETRY] = NULL, + [MESA_SHADER_FRAGMENT] = shader_key_fs_gen, +}; + +static struct zink_shader_module * +get_shader_module_for_stage(struct zink_context *ctx, struct zink_shader *zs, struct zink_gfx_program *prog) +{ + gl_shader_stage stage = zs->nir->info.stage; + struct zink_shader_key key = {}; + /* TODO: all stages should have keys and 'shader_key' below should disappear */ + void *shader_key = &key; + uint32_t key_size; + VkShaderModule mod; + struct zink_shader_module *zm; + + if (shader_key_vtbl[stage]) { + shader_key_vtbl[stage](ctx, zs, &key); + key_size = key.size; + } else { + shader_key = zs; + key_size = sizeof(void*); + } + + zm = find_cached_shader(prog, stage, key_size, shader_key); + if (!zm) { + struct keybox *keybox = make_keybox(NULL, stage, shader_key, key_size); + zm = CALLOC_STRUCT(zink_shader_module); + if (!zm) { + ralloc_free(keybox); + return NULL; + } + pipe_reference_init(&zm->reference, 1); + mod = zink_shader_compile(zink_screen(ctx->base.screen), zs, shader_key, prog->shader_slot_map, &prog->shader_slots_reserved); + if (!mod) { + ralloc_free(keybox); + FREE(zm); + return NULL; + } + zm->shader = mod; + + _mesa_hash_table_insert(prog->shader_cache, keybox, zm); + + ralloc_free(keybox); + } + return zm; +} + static void zink_destroy_shader_module(struct zink_screen *screen, struct zink_shader_module *zm) { @@ -150,12 +267,10 @@ update_shader_modules(struct zink_context *ctx, struct zink_shader *stages[ZINK_ for (int i = 0; i < ZINK_SHADER_COUNT; ++i) { enum pipe_shader_type type = pipe_shader_type_from_mesa(i); if (dirty[i]) { - prog->modules[type] = CALLOC_STRUCT(zink_shader_module); - assert(prog->modules[type]); - pipe_reference_init(&prog->modules[type]->reference, 1); + struct zink_shader_module *zm; dirty[i]->has_geometry_shader = dirty[MESA_SHADER_GEOMETRY] || stages[PIPE_SHADER_GEOMETRY]; - prog->modules[type]->shader = zink_shader_compile(zink_screen(ctx->base.screen), dirty[i], - prog->shader_slot_map, &prog->shader_slots_reserved); + zm = get_shader_module_for_stage(ctx, dirty[i], prog); + zink_shader_module_reference(zink_screen(ctx->base.screen), &prog->modules[type], zm); } else if (stages[type]) /* reuse existing shader module */ zink_shader_module_reference(zink_screen(ctx->base.screen), &prog->modules[type], ctx->curr_program->modules[type]); prog->shaders[type] = stages[type]; @@ -207,6 +322,8 @@ zink_create_gfx_program(struct zink_context *ctx, goto fail; pipe_reference_init(&prog->reference, 1); + /* we need the slot map to match up, so shaders are only cached for a given program */ + prog->shader_cache = _mesa_hash_table_create(NULL, keybox_hash, keybox_equals); init_slot_map(ctx, prog); @@ -294,6 +411,11 @@ zink_destroy_gfx_program(struct zink_screen *screen, } _mesa_hash_table_destroy(prog->pipelines[i], NULL); } + hash_table_foreach(prog->shader_cache, entry) { + struct zink_shader_module *zm = entry->data; + zink_shader_module_reference(screen, &zm, NULL); + } + _mesa_hash_table_destroy(prog->shader_cache, NULL); FREE(prog); } diff --git a/src/gallium/drivers/zink/zink_program.h b/src/gallium/drivers/zink/zink_program.h index 82900c9..0f3849c 100644 --- a/src/gallium/drivers/zink/zink_program.h +++ b/src/gallium/drivers/zink/zink_program.h @@ -44,6 +44,19 @@ struct zink_shader_module { VkShaderModule shader; }; +struct zink_fs_key { + unsigned shader_id; + //bool flat_shade; +}; + + +struct zink_shader_key { + union { + struct zink_fs_key fs; + } key; + uint32_t size; +}; + struct zink_gfx_program { struct pipe_reference reference; @@ -56,6 +69,7 @@ struct zink_gfx_program { unsigned num_descriptors; struct hash_table *pipelines[10]; // number of draw modes we support struct set *render_passes; + struct hash_table *shader_cache; }; struct zink_gfx_program * diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index d6ba712..7692763 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -50,6 +50,8 @@ struct zink_screen { struct slab_parent_pool transfer_pool; + unsigned shader_id; + VkInstance instance; VkPhysicalDevice pdev; -- 2.7.4