diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index c1e5e947148..30ac725d079 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -835,9 +835,8 @@ zink_draw_vbo(struct pipe_context *pctx, ctx->gfx_pipeline_state.primitive_topology = zink_primitive_topology(dinfo->mode); - VkPipeline pipeline = zink_create_gfx_pipeline(screen->dev, - gfx_program, - &ctx->gfx_pipeline_state); + VkPipeline pipeline = zink_get_gfx_pipeline(screen->dev, gfx_program, + &ctx->gfx_pipeline_state); bool depth_bias = false; switch (u_reduced_prim(dinfo->mode)) { @@ -965,8 +964,6 @@ zink_draw_vbo(struct pipe_context *pctx, zink_end_cmdbuf(ctx, cmdbuf); - vkDestroyPipeline(screen->dev, pipeline, NULL); - if (dinfo->index_size > 0 && dinfo->has_user_indices) pipe_resource_reference(&index_buffer, NULL); } diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 0fe94e79357..ed890b993e9 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -25,7 +25,9 @@ #include "zink_compiler.h" #include "zink_context.h" +#include "zink_screen.h" +#include "util/hash_table.h" #include "util/u_debug.h" #include "util/u_memory.h" @@ -89,15 +91,30 @@ create_pipeline_layout(VkDevice dev, VkDescriptorSetLayout dsl) return layout; } +static uint32_t +hash_gfx_pipeline_state(const void *key) +{ + return _mesa_hash_data(key, sizeof(struct zink_gfx_pipeline_state)); +} + +static bool +equals_gfx_pipeline_state(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(struct zink_gfx_pipeline_state)) == 0; +} + struct zink_gfx_program * zink_create_gfx_program(VkDevice dev, struct zink_shader *stages[PIPE_SHADER_TYPES - 1]) { struct zink_gfx_program *prog = CALLOC_STRUCT(zink_gfx_program); - if (!prog) { - debug_printf("failed to allocate gfx-program\n"); + if (!prog) + goto fail; + + prog->pipelines = _mesa_hash_table_create(NULL, hash_gfx_pipeline_state, + equals_gfx_pipeline_state); + if (!prog->pipelines) goto fail; - } for (int i = 0; i < PIPE_SHADER_TYPES - 1; ++i) prog->stages[i] = stages[i]; @@ -130,3 +147,33 @@ zink_destroy_gfx_program(VkDevice dev, struct zink_gfx_program *prog) FREE(prog); } +struct pipeline_cache_entry { + struct zink_gfx_pipeline_state state; + VkPipeline pipeline; +}; + +VkPipeline +zink_get_gfx_pipeline(VkDevice dev, struct zink_gfx_program *prog, + struct zink_gfx_pipeline_state *state) +{ + /* TODO: use pre-hashed versions to save some time (can re-hash only when + state changes) */ + struct hash_entry *entry = _mesa_hash_table_search(prog->pipelines, state); + if (!entry) { + VkPipeline pipeline = zink_create_gfx_pipeline(dev, prog, state); + if (pipeline == VK_NULL_HANDLE) + return VK_NULL_HANDLE; + + struct pipeline_cache_entry *pc_entry = CALLOC_STRUCT(pipeline_cache_entry); + if (!pc_entry) + return NULL; + + memcpy(&pc_entry->state, state, sizeof(*state)); + pc_entry->pipeline = pipeline; + + entry = _mesa_hash_table_insert(prog->pipelines, &pc_entry->state, pc_entry); + assert(entry); + } + + return ((struct pipeline_cache_entry *)(entry->data))->pipeline; +} diff --git a/src/gallium/drivers/zink/zink_program.h b/src/gallium/drivers/zink/zink_program.h index ed540fd951e..275cafa2380 100644 --- a/src/gallium/drivers/zink/zink_program.h +++ b/src/gallium/drivers/zink/zink_program.h @@ -36,6 +36,7 @@ struct zink_gfx_program { struct zink_shader *stages[PIPE_SHADER_TYPES - 1]; // compute stage doesn't belong here VkDescriptorSetLayout dsl; VkPipelineLayout layout; + struct hash_table *pipelines; }; struct zink_gfx_program * @@ -45,4 +46,8 @@ zink_create_gfx_program(VkDevice dev, void zink_destroy_gfx_program(VkDevice dev, struct zink_gfx_program *); +VkPipeline +zink_get_gfx_pipeline(VkDevice dev, struct zink_gfx_program *prog, + struct zink_gfx_pipeline_state *state); + #endif