zink: start using per-stage flags for new shaders, refcount shader modules
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Tue, 30 Jun 2020 13:57:19 +0000 (09:57 -0400)
committerMarge Bot <eric+marge@anholt.net>
Fri, 7 Aug 2020 12:36:59 +0000 (12:36 +0000)
we don't want to recompile shaders if we don't have to, so we can set bitflags
upon receiving new shader states and then compile only the stages that have
changed while refcounting the unchanged stages

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5970>

src/gallium/drivers/zink/zink_context.c
src/gallium/drivers/zink/zink_context.h
src/gallium/drivers/zink/zink_draw.c
src/gallium/drivers/zink/zink_pipeline.c
src/gallium/drivers/zink/zink_program.c
src/gallium/drivers/zink/zink_program.h

index 9098765bb9c1a3d93adb70801cc8c4859352aeaf..c5ec154cf3ce9a4920e1121381021106f79660d8 100644 (file)
@@ -1178,8 +1178,6 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
    if (!ctx->dummy_buffer)
       goto fail;
 
-   ctx->dirty_program = true;
-
    /* start the first batch */
    zink_start_batch(ctx, zink_curr_batch(ctx));
 
index b403bc92a85303d2db5dbaca4792560f34a155aa..a9c3b718cee8368243ab7b15a5a6db80f6fccefb 100644 (file)
@@ -95,7 +95,7 @@ struct zink_context {
    struct hash_table *program_cache;
    struct zink_gfx_program *curr_program;
 
-   unsigned dirty_program : 1;
+   unsigned dirty_shader_stages : 6; /* mask of changed shader stages */
 
    struct hash_table *render_pass_cache;
 
index 79e61ccb52bbe51b310bca0e04d6612fed70642a..9ce51ea0beeaa9b9298ff4b3e270614e014dce3f 100644 (file)
@@ -160,7 +160,7 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
 static struct zink_gfx_program *
 get_gfx_program(struct zink_context *ctx)
 {
-   if (ctx->dirty_program) {
+   if (ctx->dirty_shader_stages) {
       struct hash_entry *entry = _mesa_hash_table_search(ctx->program_cache,
                                                          ctx->gfx_stages);
       if (!entry) {
@@ -171,7 +171,7 @@ get_gfx_program(struct zink_context *ctx)
             return NULL;
       }
       ctx->curr_program = entry->data;
-      ctx->dirty_program = false;
+      ctx->dirty_shader_stages = 0;
    }
 
    assert(ctx->curr_program);
index af38c84aeafadbf784ebd27f6222ebaba8899872..637e880eb3ce6b5afa0821ee8f0826373ca50821 100644 (file)
@@ -149,7 +149,7 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
       VkPipelineShaderStageCreateInfo stage = {};
       stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
       stage.stage = zink_shader_stage(i);
-      stage.module = prog->stages[i];
+      stage.module = prog->stages[i]->shader;
       stage.pName = "main";
       shader_stages[num_stages++] = stage;
    }
index ee735a810d28d0dd526790d5a7781248bde21283..f6b3acdc84d20cab17b5a68e6bb64f5c69d929c8 100644 (file)
@@ -45,6 +45,12 @@ debug_describe_zink_gfx_program(char *buf, const struct zink_gfx_program *ptr)
    sprintf(buf, "zink_gfx_program");
 }
 
+static void
+debug_describe_zink_shader_module(char *buf, const struct zink_shader_module *ptr)
+{
+   sprintf(buf, "zink_shader_module");
+}
+
 static VkDescriptorSetLayout
 create_desc_set_layout(VkDevice dev,
                        struct zink_shader *stages[ZINK_SHADER_COUNT],
@@ -107,15 +113,47 @@ create_pipeline_layout(VkDevice dev, VkDescriptorSetLayout dsl)
    return layout;
 }
 
+static void
+zink_destroy_shader_module(struct zink_screen *screen, struct zink_shader_module *zm)
+{
+   vkDestroyShaderModule(screen->dev, zm->shader, NULL);
+   free(zm);
+}
+
+static inline void
+zink_shader_module_reference(struct zink_screen *screen,
+                           struct zink_shader_module **dst,
+                           struct zink_shader_module *src)
+{
+   struct zink_shader_module *old_dst = dst ? *dst : NULL;
+
+   if (pipe_reference_described(old_dst ? &old_dst->reference : NULL, &src->reference,
+                                (debug_reference_descriptor)debug_describe_zink_shader_module))
+      zink_destroy_shader_module(screen, old_dst);
+   if (dst) *dst = src;
+}
+
 static void
 update_shader_modules(struct zink_context *ctx, struct zink_shader *stages[ZINK_SHADER_COUNT], struct zink_gfx_program *prog)
 {
+   struct zink_shader *dirty[ZINK_SHADER_COUNT] = {NULL};
+
+   unsigned dirty_shader_stages = ctx->dirty_shader_stages;
+   while (dirty_shader_stages) {
+      unsigned type = u_bit_scan(&dirty_shader_stages);
+      dirty[type] = stages[type];
+   }
    for (int i = 0; i < ZINK_SHADER_COUNT; ++i) {
-      if (stages[i]) {
-         prog->stages[i] = zink_shader_compile(zink_screen(ctx->base.screen), stages[i]);
-         prog->shaders[i] = stages[i];
-      }
+      if (dirty[i]) {
+         prog->stages[i] = CALLOC_STRUCT(zink_shader_module);
+         assert(prog->stages[i]);
+         pipe_reference_init(&prog->stages[i]->reference, 1);
+         prog->stages[i]->shader = zink_shader_compile(zink_screen(ctx->base.screen), stages[i]);
+      } else if (stages[i]) /* reuse existing shader module */
+         zink_shader_module_reference(zink_screen(ctx->base.screen), &prog->stages[i], ctx->curr_program->stages[i]);
+      prog->shaders[i] = stages[i];
    }
+   ctx->dirty_shader_stages = 0;
 }
 
 static uint32_t
@@ -204,7 +242,7 @@ zink_destroy_gfx_program(struct zink_screen *screen,
       if (prog->shaders[i])
          gfx_program_remove_shader(prog, prog->shaders[i]);
       if (prog->stages[i])
-         vkDestroyShaderModule(screen->dev, prog->stages[i], NULL);
+         zink_shader_module_reference(screen, &prog->stages[i], NULL);
    }
 
    /* unref all used render-passes */
@@ -323,7 +361,7 @@ bind_stage(struct zink_context *ctx, enum pipe_shader_type stage,
 {
    assert(stage < PIPE_SHADER_COMPUTE);
    ctx->gfx_stages[stage] = shader;
-   ctx->dirty_program = true;
+   ctx->dirty_shader_stages |= 1 << stage;
 }
 
 static void
index 1d4aaa0cfdc7102ab133fcde4a27b2245ad20536..c82d409d6735968420704dbe7d972626db7ad770 100644 (file)
@@ -38,10 +38,15 @@ struct zink_gfx_pipeline_state;
 struct hash_table;
 struct set;
 
+struct zink_shader_module {
+   struct pipe_reference reference;
+   VkShaderModule shader;
+};
+
 struct zink_gfx_program {
    struct pipe_reference reference;
 
-   VkShaderModule stages[ZINK_SHADER_COUNT]; // compute stage doesn't belong here
+   struct zink_shader_module *stages[ZINK_SHADER_COUNT]; // compute stage doesn't belong here
    struct zink_shader *shaders[ZINK_SHADER_COUNT];
    VkDescriptorSetLayout dsl;
    VkPipelineLayout layout;