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
