Mesa (main): iris: Add the variant to the list as early as possible

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jul 28 18:00:25 UTC 2021


Module: Mesa
Branch: main
Commit: 2024d470483d85a0b954d1c614b0af8eeb95d993
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=2024d470483d85a0b954d1c614b0af8eeb95d993

Author: Ian Romanick <ian.d.romanick at intel.com>
Date:   Wed Jun  2 14:30:08 2021 -0700

iris: Add the variant to the list as early as possible

I tried to find a way to break this into some smaller commits, but
everything is very intertwined. :(

When searching the variants list in the iris_uncompiled_shader, add the
new variant if it is not found.  This will be necessary for threaded
shader compilation.  This conceptually simple change had a bunch of
fallout.

Much of this was at least conceptually borrowed from radeonsi.

- Other threads might find a variant in the list before the variant has
  been compiled.  To accomdate this, add a fence.  Each thread will wait
  on the fence in the variant when searching the list.

- A variant in the list may fail compilation.  To accomodate this, add a
  flag.  All paths will examine iris_compiled_shader::compilation_failed
  before trying to use the variant.

- The race condition between multiple threads trying to create the same
  variant at the same time is handled *before* both thread spend the
  effort to compile the shader.  The means that iris_upload_shader
  cannot change shaders on the caller, so it does not need to return
  anything.

v2: Change "found" parameter of find_or_add_variant to "added."  This
inverts the values returned, and it probably makes uses of the returned
value more easily understood.  Always set the value in the called
function.  Suggested by Ken.

v3: Move shader->compilation_failed check to avoid shader != NULL test.
Rearrange some logic and add a comment in iris_update_compiled_tcs.
Suggested by Ken.  Don't call find_or_add_variant in
iris_create_shader_state.  See
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11229#note_1000843
for more details.  Noticed by Ken.

Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11229>

---

 src/gallium/drivers/iris/iris_context.h       |  47 ++--
 src/gallium/drivers/iris/iris_disk_cache.c    |  26 +-
 src/gallium/drivers/iris/iris_program.c       | 327 ++++++++++++++++----------
 src/gallium/drivers/iris/iris_program_cache.c |  29 +--
 4 files changed, 249 insertions(+), 180 deletions(-)

diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h
index c9dd66b988b..626db8c2f17 100644
--- a/src/gallium/drivers/iris/iris_context.h
+++ b/src/gallium/drivers/iris/iris_context.h
@@ -460,6 +460,18 @@ struct iris_compiled_shader {
    /** Key for this variant (but not for BLORP programs) */
    union iris_any_prog_key key;
 
+   /**
+    * Is the variant fully compiled and ready?
+    *
+    * Variants are added to \c iris_uncompiled_shader::variants before
+    * compilation actually occurs.  This signals that compilation has
+    * completed.
+    */
+   struct util_queue_fence ready;
+
+   /** Variant is ready, but compilation failed. */
+   bool compilation_failed;
+
    /** Reference to the uploaded assembly. */
    struct iris_state_ref assembly;
 
@@ -925,10 +937,11 @@ void iris_disk_cache_store(struct disk_cache *cache,
                            const struct iris_compiled_shader *shader,
                            const void *prog_key,
                            uint32_t prog_key_size);
-struct iris_compiled_shader *
+bool
 iris_disk_cache_retrieve(struct iris_screen *screen,
                          struct u_upload_mgr *uploader,
                          struct iris_uncompiled_shader *ish,
+                         struct iris_compiled_shader *shader,
                          const void *prog_key,
                          uint32_t prog_key_size);
 
@@ -947,22 +960,22 @@ struct iris_compiled_shader *iris_create_shader_variant(const struct iris_screen
                                                         uint32_t key_size,
                                                         const void *key);
 
-struct iris_compiled_shader *iris_upload_shader(struct iris_screen *screen,
-                                                struct iris_uncompiled_shader *,
-                                                struct iris_compiled_shader *,
-                                                struct hash_table *driver_ht,
-                                                struct u_upload_mgr *uploader,
-                                                enum iris_program_cache_id,
-                                                uint32_t key_size,
-                                                const void *key,
-                                                const void *assembly,
-                                                struct brw_stage_prog_data *,
-                                                uint32_t *streamout,
-                                                enum brw_param_builtin *sysv,
-                                                unsigned num_system_values,
-                                                unsigned kernel_input_size,
-                                                unsigned num_cbufs,
-                                                const struct iris_binding_table *bt);
+void iris_upload_shader(struct iris_screen *screen,
+                        struct iris_uncompiled_shader *,
+                        struct iris_compiled_shader *,
+                        struct hash_table *driver_ht,
+                        struct u_upload_mgr *uploader,
+                        enum iris_program_cache_id,
+                        uint32_t key_size,
+                        const void *key,
+                        const void *assembly,
+                        struct brw_stage_prog_data *,
+                        uint32_t *streamout,
+                        enum brw_param_builtin *sysv,
+                        unsigned num_system_values,
+                        unsigned kernel_input_size,
+                        unsigned num_cbufs,
+                        const struct iris_binding_table *bt);
 void iris_delete_shader_variant(struct iris_compiled_shader *shader);
 
 void iris_destroy_shader_state(struct pipe_context *ctx, void *state);
diff --git a/src/gallium/drivers/iris/iris_disk_cache.c b/src/gallium/drivers/iris/iris_disk_cache.c
index 3be0301b1ef..62313edde31 100644
--- a/src/gallium/drivers/iris/iris_disk_cache.c
+++ b/src/gallium/drivers/iris/iris_disk_cache.c
@@ -141,10 +141,11 @@ static const enum iris_program_cache_id cache_id_for_stage[] = {
  * Search for a compiled shader in the disk cache.  If found, upload it
  * to the in-memory program cache so we can use it.
  */
-struct iris_compiled_shader *
+bool
 iris_disk_cache_retrieve(struct iris_screen *screen,
                          struct u_upload_mgr *uploader,
                          struct iris_uncompiled_shader *ish,
+                         struct iris_compiled_shader *shader,
                          const void *prog_key,
                          uint32_t key_size)
 {
@@ -153,7 +154,7 @@ iris_disk_cache_retrieve(struct iris_screen *screen,
    gl_shader_stage stage = ish->nir->info.stage;
 
    if (!cache)
-      return NULL;
+      return false;
 
    cache_key cache_key;
    iris_disk_cache_compute_key(cache, ish, prog_key, key_size, cache_key);
@@ -171,7 +172,7 @@ iris_disk_cache_retrieve(struct iris_screen *screen,
       fprintf(stderr, "%s\n", buffer ? "found" : "missing");
 
    if (!buffer)
-      return NULL;
+      return false;
 
    const uint32_t prog_data_size = brw_prog_data_size(stage);
 
@@ -241,22 +242,17 @@ iris_disk_cache_retrieve(struct iris_screen *screen,
    assert(stage < ARRAY_SIZE(cache_id_for_stage));
    enum iris_program_cache_id cache_id = cache_id_for_stage[stage];
 
-   /* Upload our newly read shader to the in-memory program cache and
-    * return it to the caller.
-    */
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, cache_id, key_size, prog_key);
-
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               cache_id, key_size, prog_key, assembly,
-                               prog_data, so_decls, system_values,
-                               num_system_values, kernel_input_size, num_cbufs, &bt);
+   /* Upload our newly read shader to the in-memory program cache. */
+   iris_upload_shader(screen, ish, shader, NULL, uploader,
+                      cache_id, key_size, prog_key, assembly,
+                      prog_data, so_decls, system_values,
+                      num_system_values, kernel_input_size, num_cbufs, &bt);
 
    free(buffer);
 
-   return shader;
+   return true;
 #else
-   return NULL;
+   return false;
 #endif
 }
 
diff --git a/src/gallium/drivers/iris/iris_program.c b/src/gallium/drivers/iris/iris_program.c
index 0f4c83feaf7..6fae0b5b794 100644
--- a/src/gallium/drivers/iris/iris_program.c
+++ b/src/gallium/drivers/iris/iris_program.c
@@ -1107,13 +1107,22 @@ last_vue_stage(struct iris_context *ice)
    return MESA_SHADER_VERTEX;
 }
 
+/**
+ * \param added  Set to \c true if the variant was added to the list (i.e., a
+ *               variant matching \c key was not found).  Set to \c false
+ *               otherwise.
+ */
 static inline struct iris_compiled_shader *
-find_variant(const struct iris_screen *screen,
-             struct iris_uncompiled_shader *ish,
-             const void *key, unsigned key_size)
+find_or_add_variant(const struct iris_screen *screen,
+                    struct iris_uncompiled_shader *ish,
+                    enum iris_program_cache_id cache_id,
+                    const void *key, unsigned key_size,
+                    bool *added)
 {
    struct list_head *start = ish->variants.next;
 
+   *added = false;
+
    if (screen->precompile) {
       /* Check the first list entry.  There will always be at least one
        * variant in the list (most likely the precompile variant), and
@@ -1123,8 +1132,10 @@ find_variant(const struct iris_screen *screen,
       struct iris_compiled_shader *first =
          list_first_entry(&ish->variants, struct iris_compiled_shader, link);
 
-      if (memcmp(&first->key, key, key_size) == 0)
+      if (memcmp(&first->key, key, key_size) == 0) {
+         util_queue_fence_wait(&first->ready);
          return first;
+      }
 
       /* Skip this one in the loop below */
       start = first->link.next;
@@ -1145,7 +1156,20 @@ find_variant(const struct iris_screen *screen,
       }
    }
 
-   simple_mtx_unlock(&ish->lock);
+   if (variant == NULL) {
+      variant = iris_create_shader_variant(screen, NULL, cache_id,
+                                           key_size, key);
+
+      /* Append our new variant to the shader's variant list. */
+      list_addtail(&variant->link, &ish->variants);
+      *added = true;
+
+      simple_mtx_unlock(&ish->lock);
+   } else {
+      simple_mtx_unlock(&ish->lock);
+
+      util_queue_fence_wait(&variant->ready);
+   }
 
    return variant;
 }
@@ -1153,11 +1177,12 @@ find_variant(const struct iris_screen *screen,
 /**
  * Compile a vertex shader, and upload the assembly.
  */
-static struct iris_compiled_shader *
+static void
 iris_compile_vs(struct iris_screen *screen,
                 struct u_upload_mgr *uploader,
                 struct pipe_debug_callback *dbg,
                 struct iris_uncompiled_shader *ish,
+                struct iris_compiled_shader *shader,
                 const struct iris_vs_prog_key *key)
 {
    const struct brw_compiler *compiler = screen->compiler;
@@ -1211,27 +1236,28 @@ iris_compile_vs(struct iris_screen *screen,
    if (program == NULL) {
       dbg_printf("Failed to compile vertex shader: %s\n", params.error_str);
       ralloc_free(mem_ctx);
-      return NULL;
+
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
    }
 
+   shader->compilation_failed = false;
+
    iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
    uint32_t *so_decls =
       screen->vtbl.create_so_decl_list(&ish->stream_output,
                                     &vue_prog_data->vue_map);
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, IRIS_CACHE_VS, sizeof(*key), key);
-
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               IRIS_CACHE_VS, sizeof(*key), key, program,
-                               prog_data, so_decls, system_values, num_system_values,
-                               0, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, NULL, uploader, IRIS_CACHE_VS,
+                      sizeof(*key), key, program, prog_data, so_decls,
+                      system_values, num_system_values, 0, num_cbufs, &bt);
 
    iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 /**
@@ -1252,16 +1278,17 @@ iris_update_compiled_vs(struct iris_context *ice)
    screen->vtbl.populate_vs_key(ice, &ish->nir->info, last_vue_stage(ice), &key);
 
    struct iris_compiled_shader *old = ice->shaders.prog[IRIS_CACHE_VS];
+   bool added;
    struct iris_compiled_shader *shader =
-      find_variant(screen, ish, &key, sizeof(key));
+      find_or_add_variant(screen, ish, IRIS_CACHE_VS, &key, sizeof(key), &added);
 
-   if (!shader) {
-      shader = iris_disk_cache_retrieve(screen, uploader, ish,
-                                        &key, sizeof(key));
+   if (added && !iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                          &key, sizeof(key))) {
+      iris_compile_vs(screen, uploader, &ice->dbg, ish, shader, &key);
    }
 
-   if (!shader)
-      shader = iris_compile_vs(screen, uploader, &ice->dbg, ish, &key);
+   if (shader->compilation_failed)
+      shader = NULL;
 
    if (old != shader) {
       iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_VERTEX],
@@ -1327,12 +1354,13 @@ get_unified_tess_slots(const struct iris_context *ice,
 /**
  * Compile a tessellation control shader, and upload the assembly.
  */
-static struct iris_compiled_shader *
+static void
 iris_compile_tcs(struct iris_screen *screen,
                  struct hash_table *passthrough_ht,
                  struct u_upload_mgr *uploader,
                  struct pipe_debug_callback *dbg,
                  struct iris_uncompiled_shader *ish,
+                 struct iris_compiled_shader *shader,
                  const struct iris_tcs_prog_key *key)
 {
    const struct brw_compiler *compiler = screen->compiler;
@@ -1407,27 +1435,26 @@ iris_compile_tcs(struct iris_screen *screen,
    if (program == NULL) {
       dbg_printf("Failed to compile control shader: %s\n", error_str);
       ralloc_free(mem_ctx);
-      return NULL;
-   }
 
-   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
+   }
 
-   void *passthrough_mem_ctx = (ish != NULL) ? NULL : passthrough_ht;
+   shader->compilation_failed = false;
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, passthrough_mem_ctx, IRIS_CACHE_TCS,
-                                 sizeof(*key), key);
+   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
-   shader = iris_upload_shader(screen, ish, shader, passthrough_ht, uploader,
-                               IRIS_CACHE_TCS, sizeof(*key), key, program,
-                               prog_data, NULL, system_values, num_system_values,
-                               0, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, passthrough_ht, uploader,
+                      IRIS_CACHE_TCS, sizeof(*key), key, program, prog_data,
+                      NULL, system_values, num_system_values, 0, num_cbufs,
+                      &bt);
 
    if (ish)
       iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 /**
@@ -1462,20 +1489,39 @@ iris_update_compiled_tcs(struct iris_context *ice)
    screen->vtbl.populate_tcs_key(ice, &key);
 
    struct iris_compiled_shader *old = ice->shaders.prog[IRIS_CACHE_TCS];
-   struct iris_compiled_shader *shader =
-      tcs ? find_variant(screen, tcs, &key, sizeof(key)) :
-      iris_find_cached_shader(ice, IRIS_CACHE_TCS, sizeof(key), &key);
+   struct iris_compiled_shader *shader;
+   bool added = false;
+
+   if (tcs != NULL) {
+      shader = find_or_add_variant(screen, tcs, IRIS_CACHE_TCS, &key,
+                                   sizeof(key), &added);
+   } else {
+      /* Look for and possibly create a passthrough TCS */
+      shader = iris_find_cached_shader(ice, IRIS_CACHE_TCS, sizeof(key), &key);
+
+
+      if (shader == NULL) {
+         shader = iris_create_shader_variant(screen, ice->shaders.cache,
+                                             IRIS_CACHE_TCS, sizeof(key), &key);
+         added = true;
+      }
 
-   if (tcs && !shader) {
-      shader = iris_disk_cache_retrieve(screen, uploader, tcs,
-                                        &key, sizeof(key));
    }
 
-   if (!shader) {
-      shader = iris_compile_tcs(screen, ice->shaders.cache,
-                                uploader, &ice->dbg, tcs, &key);
+   /* If the shader was not found in (whichever cache), call iris_compile_tcs
+    * if either ish is NULL or the shader could not be found in the disk
+    * cache.
+    */
+   if (added &&
+       (tcs == NULL || !iris_disk_cache_retrieve(screen, uploader, tcs, shader,
+                                                 &key, sizeof(key)))) {
+      iris_compile_tcs(screen, ice->shaders.cache, uploader, &ice->dbg, tcs,
+                       shader, &key);
    }
 
+   if (shader->compilation_failed)
+      shader = NULL;
+
    if (old != shader) {
       iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_CTRL],
                                     shader);
@@ -1492,11 +1538,12 @@ iris_update_compiled_tcs(struct iris_context *ice)
 /**
  * Compile a tessellation evaluation shader, and upload the assembly.
  */
-static struct iris_compiled_shader *
+static void
 iris_compile_tes(struct iris_screen *screen,
                  struct u_upload_mgr *uploader,
                  struct pipe_debug_callback *dbg,
                  struct iris_uncompiled_shader *ish,
+                 struct iris_compiled_shader *shader,
                  const struct iris_tes_prog_key *key)
 {
    const struct brw_compiler *compiler = screen->compiler;
@@ -1544,27 +1591,28 @@ iris_compile_tes(struct iris_screen *screen,
    if (program == NULL) {
       dbg_printf("Failed to compile evaluation shader: %s\n", error_str);
       ralloc_free(mem_ctx);
-      return NULL;
+
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
    }
 
+   shader->compilation_failed = false;
+
    iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
    uint32_t *so_decls =
       screen->vtbl.create_so_decl_list(&ish->stream_output,
                                     &vue_prog_data->vue_map);
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, IRIS_CACHE_TES, sizeof(*key), key);
-
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               IRIS_CACHE_TES, sizeof(*key), key, program,
-                               prog_data, so_decls, system_values, num_system_values,
-                               0, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, NULL, uploader, IRIS_CACHE_TES,
+                      sizeof(*key), key, program, prog_data, so_decls,
+                      system_values, num_system_values, 0, num_cbufs, &bt);
 
    iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 /**
@@ -1586,16 +1634,17 @@ iris_update_compiled_tes(struct iris_context *ice)
    screen->vtbl.populate_tes_key(ice, &ish->nir->info, last_vue_stage(ice), &key);
 
    struct iris_compiled_shader *old = ice->shaders.prog[IRIS_CACHE_TES];
+   bool added;
    struct iris_compiled_shader *shader =
-      find_variant(screen, ish, &key, sizeof(key));
+      find_or_add_variant(screen, ish, IRIS_CACHE_TES, &key, sizeof(key), &added);
 
-   if (!shader) {
-      shader = iris_disk_cache_retrieve(screen, uploader, ish,
-                                        &key, sizeof(key));
+   if (added && !iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                          &key, sizeof(key))) {
+      iris_compile_tes(screen, uploader, &ice->dbg, ish, shader, &key);
    }
 
-   if (!shader)
-      shader = iris_compile_tes(screen, uploader, &ice->dbg, ish, &key);
+   if (shader->compilation_failed)
+      shader = NULL;
 
    if (old != shader) {
       iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_TESS_EVAL],
@@ -1620,11 +1669,12 @@ iris_update_compiled_tes(struct iris_context *ice)
 /**
  * Compile a geometry shader, and upload the assembly.
  */
-static struct iris_compiled_shader *
+static void
 iris_compile_gs(struct iris_screen *screen,
                 struct u_upload_mgr *uploader,
                 struct pipe_debug_callback *dbg,
                 struct iris_uncompiled_shader *ish,
+                struct iris_compiled_shader *shader,
                 const struct iris_gs_prog_key *key)
 {
    const struct brw_compiler *compiler = screen->compiler;
@@ -1672,27 +1722,28 @@ iris_compile_gs(struct iris_screen *screen,
    if (program == NULL) {
       dbg_printf("Failed to compile geometry shader: %s\n", error_str);
       ralloc_free(mem_ctx);
-      return NULL;
+
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
    }
 
+   shader->compilation_failed = false;
+
    iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
    uint32_t *so_decls =
       screen->vtbl.create_so_decl_list(&ish->stream_output,
                                     &vue_prog_data->vue_map);
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, IRIS_CACHE_GS, sizeof(*key), key);
-
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               IRIS_CACHE_GS, sizeof(*key), key, program,
-                               prog_data, so_decls, system_values, num_system_values,
-                               0, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, NULL, uploader, IRIS_CACHE_GS,
+                      sizeof(*key), key, program, prog_data, so_decls,
+                      system_values, num_system_values, 0, num_cbufs, &bt);
 
    iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 /**
@@ -1715,15 +1766,18 @@ iris_update_compiled_gs(struct iris_context *ice)
       struct iris_gs_prog_key key = { KEY_ID(vue.base) };
       screen->vtbl.populate_gs_key(ice, &ish->nir->info, last_vue_stage(ice), &key);
 
-      shader = find_variant(screen, ish, &key, sizeof(key));
+      bool added;
 
-      if (!shader) {
-         shader = iris_disk_cache_retrieve(screen, uploader, ish,
-                                           &key, sizeof(key));
+      shader = find_or_add_variant(screen, ish, IRIS_CACHE_GS, &key,
+                                   sizeof(key), &added);
+
+      if (added && !iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                             &key, sizeof(key))) {
+         iris_compile_gs(screen, uploader, &ice->dbg, ish, shader, &key);
       }
 
-      if (!shader)
-         shader = iris_compile_gs(screen, uploader, &ice->dbg, ish, &key);
+      if (shader->compilation_failed)
+         shader = NULL;
    }
 
    if (old != shader) {
@@ -1743,11 +1797,12 @@ iris_update_compiled_gs(struct iris_context *ice)
 /**
  * Compile a fragment (pixel) shader, and upload the assembly.
  */
-static struct iris_compiled_shader *
+static void
 iris_compile_fs(struct iris_screen *screen,
                 struct u_upload_mgr *uploader,
                 struct pipe_debug_callback *dbg,
                 struct iris_uncompiled_shader *ish,
+                struct iris_compiled_shader *shader,
                 const struct iris_fs_prog_key *key,
                 struct brw_vue_map *vue_map)
 {
@@ -1805,23 +1860,24 @@ iris_compile_fs(struct iris_screen *screen,
    if (program == NULL) {
       dbg_printf("Failed to compile fragment shader: %s\n", params.error_str);
       ralloc_free(mem_ctx);
-      return NULL;
+
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
    }
 
-   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
+   shader->compilation_failed = false;
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, IRIS_CACHE_FS, sizeof(*key), key);
+   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               IRIS_CACHE_FS, sizeof(*key), key, program,
-                               prog_data, NULL, system_values, num_system_values,
-                               0, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, NULL, uploader, IRIS_CACHE_FS,
+                      sizeof(*key), key, program, prog_data, NULL,
+                      system_values, num_system_values, 0, num_cbufs, &bt);
 
    iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 /**
@@ -1847,18 +1903,19 @@ iris_update_compiled_fs(struct iris_context *ice)
       key.input_slots_valid = last_vue_map->slots_valid;
 
    struct iris_compiled_shader *old = ice->shaders.prog[IRIS_CACHE_FS];
+   bool added;
    struct iris_compiled_shader *shader =
-      find_variant(screen, ish, &key, sizeof(key));
+      find_or_add_variant(screen, ish, IRIS_CACHE_FS, &key,
+                          sizeof(key), &added);
 
-   if (!shader) {
-      shader = iris_disk_cache_retrieve(screen, uploader, ish,
-                                        &key, sizeof(key));
+   if (added && !iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                          &key, sizeof(key))) {
+      iris_compile_fs(screen, uploader, &ice->dbg, ish, shader, &key,
+                      last_vue_map);
    }
 
-   if (!shader) {
-      shader = iris_compile_fs(screen, uploader, &ice->dbg,
-                               ish, &key, last_vue_map);
-   }
+   if (shader->compilation_failed)
+      shader = NULL;
 
    if (old != shader) {
       // XXX: only need to flag CLIP if barycentric has NONPERSPECTIVE
@@ -2032,11 +2089,12 @@ iris_update_compiled_shaders(struct iris_context *ice)
    }
 }
 
-static struct iris_compiled_shader *
+static void
 iris_compile_cs(struct iris_screen *screen,
                 struct u_upload_mgr *uploader,
                 struct pipe_debug_callback *dbg,
                 struct iris_uncompiled_shader *ish,
+                struct iris_compiled_shader *shader,
                 const struct iris_cs_prog_key *key)
 {
    const struct brw_compiler *compiler = screen->compiler;
@@ -2073,24 +2131,25 @@ iris_compile_cs(struct iris_screen *screen,
    const unsigned *program = brw_compile_cs(compiler, mem_ctx, &params);
    if (program == NULL) {
       dbg_printf("Failed to compile compute shader: %s\n", params.error_str);
-      ralloc_free(mem_ctx);
-      return false;
+
+      shader->compilation_failed = true;
+      util_queue_fence_signal(&shader->ready);
+
+      return;
    }
 
-   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
+   shader->compilation_failed = false;
 
-   struct iris_compiled_shader *shader =
-      iris_create_shader_variant(screen, NULL, IRIS_CACHE_CS, sizeof(*key), key);
+   iris_debug_recompile(screen, dbg, ish, &brw_key.base);
 
-   shader = iris_upload_shader(screen, ish, shader, NULL, uploader,
-                               IRIS_CACHE_CS, sizeof(*key), key, program,
-                               prog_data, NULL, system_values, num_system_values,
-                               ish->kernel_input_size, num_cbufs, &bt);
+   iris_upload_shader(screen, ish, shader, NULL, uploader, IRIS_CACHE_CS,
+                      sizeof(*key), key, program, prog_data, NULL,
+                      system_values, num_system_values, ish->kernel_input_size,
+                      num_cbufs, &bt);
 
    iris_disk_cache_store(screen->disk_cache, ish, shader, key, sizeof(*key));
 
    ralloc_free(mem_ctx);
-   return shader;
 }
 
 static void
@@ -2106,16 +2165,18 @@ iris_update_compiled_cs(struct iris_context *ice)
    screen->vtbl.populate_cs_key(ice, &key);
 
    struct iris_compiled_shader *old = ice->shaders.prog[IRIS_CACHE_CS];
+   bool added;
    struct iris_compiled_shader *shader =
-      find_variant(screen, ish, &key, sizeof(key));
+      find_or_add_variant(screen, ish, IRIS_CACHE_CS, &key,
+                          sizeof(key), &added);
 
-   if (!shader) {
-      shader = iris_disk_cache_retrieve(screen, uploader, ish,
-                                        &key, sizeof(key));
+   if (added && !iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                          &key, sizeof(key))) {
+      iris_compile_cs(screen, uploader, &ice->dbg, ish, shader, &key);
    }
 
-   if (!shader)
-      shader = iris_compile_cs(screen, uploader, &ice->dbg, ish, &key);
+   if (shader->compilation_failed)
+      shader = NULL;
 
    if (old != shader) {
       iris_shader_variant_reference(&ice->shaders.prog[MESA_SHADER_COMPUTE],
@@ -2383,8 +2444,14 @@ iris_create_compute_state(struct pipe_context *ctx,
    if (screen->precompile) {
       struct iris_cs_prog_key key = { KEY_ID(base) };
 
-      if (!iris_disk_cache_retrieve(screen, uploader, ish, &key, sizeof(key)))
-         iris_compile_cs(screen, uploader, &ice->dbg, ish, &key);
+      struct iris_compiled_shader *shader =
+         iris_create_shader_variant(screen, NULL, IRIS_CACHE_CS,
+                                    sizeof(key), &key);
+
+      if (!iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                    &key, sizeof(key))) {
+         iris_compile_cs(screen, uploader, &ice->dbg, ish, shader, &key);
+      }
    }
 
    return ish;
@@ -2395,28 +2462,28 @@ iris_compile_shader(struct iris_screen *screen,
                     struct u_upload_mgr *uploader,
                     struct pipe_debug_callback *dbg,
                     struct iris_uncompiled_shader *ish,
-                    const void *key)
+                    struct iris_compiled_shader *shader)
 {
    switch (ish->nir->info.stage) {
    case MESA_SHADER_VERTEX:
-      iris_compile_vs(screen, uploader, dbg, ish,
-                      (const struct iris_vs_prog_key *) key);
+      iris_compile_vs(screen, uploader, dbg, ish, shader,
+                      &shader->key.vs);
       break;
    case MESA_SHADER_TESS_CTRL:
-      iris_compile_tcs(screen, NULL, uploader, dbg, ish,
-                       (const struct iris_tcs_prog_key *) key);
+      iris_compile_tcs(screen, NULL, uploader, dbg, ish, shader,
+                       &shader->key.tcs);
       break;
    case MESA_SHADER_TESS_EVAL:
-      iris_compile_tes(screen, uploader, dbg, ish,
-                       (const struct iris_tes_prog_key *) key);
+      iris_compile_tes(screen, uploader, dbg, ish, shader,
+                       &shader->key.tes);
       break;
    case MESA_SHADER_GEOMETRY:
-      iris_compile_gs(screen, uploader, dbg, ish,
-                      (const struct iris_gs_prog_key *) key);
+      iris_compile_gs(screen, uploader, dbg, ish, shader,
+                      &shader->key.gs);
       break;
    case MESA_SHADER_FRAGMENT:
-      iris_compile_fs(screen, uploader, dbg, ish,
-                      (const struct iris_fs_prog_key *) key, NULL);
+      iris_compile_fs(screen, uploader, dbg, ish, shader,
+                      &shader->key.fs, NULL);
       break;
 
    default:
@@ -2544,8 +2611,18 @@ iris_create_shader_state(struct pipe_context *ctx,
    if (screen->precompile) {
       struct u_upload_mgr *uploader = ice->shaders.uploader_unsync;
 
-      if (!iris_disk_cache_retrieve(screen, uploader, ish, &key, key_size))
-         iris_compile_shader(screen, uploader, &ice->dbg, ish, &key);
+      struct iris_compiled_shader *shader =
+         iris_create_shader_variant(screen, NULL,
+                                    (enum iris_program_cache_id) info->stage,
+                                    key_size, &key);
+
+      /* Append our new variant to the shader's variant list. */
+      list_addtail(&shader->link, &ish->variants);
+
+      if (!iris_disk_cache_retrieve(screen, uploader, ish, shader,
+                                    &key, key_size)) {
+         iris_compile_shader(screen, uploader, &ice->dbg, ish, shader);
+      }
    }
 
    return ish;
diff --git a/src/gallium/drivers/iris/iris_program_cache.c b/src/gallium/drivers/iris/iris_program_cache.c
index 235cf99e8ef..bb8795403cb 100644
--- a/src/gallium/drivers/iris/iris_program_cache.c
+++ b/src/gallium/drivers/iris/iris_program_cache.c
@@ -103,6 +103,7 @@ void
 iris_delete_shader_variant(struct iris_compiled_shader *shader)
 {
    pipe_resource_reference(&shader->assembly.res, NULL);
+   util_queue_fence_destroy(&shader->ready);
    ralloc_free(shader);
 }
 
@@ -134,6 +135,8 @@ iris_create_shader_variant(const struct iris_screen *screen,
                    screen->vtbl.derived_program_state_size(cache_id));
 
    pipe_reference_init(&shader->ref, 1);
+   util_queue_fence_init(&shader->ready);
+   util_queue_fence_reset(&shader->ready);
 
    if (cache_id != IRIS_CACHE_BLORP) {
       assert(key_size <= sizeof(union iris_any_prog_key));
@@ -143,7 +146,7 @@ iris_create_shader_variant(const struct iris_screen *screen,
    return shader;
 }
 
-struct iris_compiled_shader *
+void
 iris_upload_shader(struct iris_screen *screen,
                    struct iris_uncompiled_shader *ish,
                    struct iris_compiled_shader *shader,
@@ -204,32 +207,12 @@ iris_upload_shader(struct iris_screen *screen,
    /* Store the 3DSTATE shader packets and other derived state. */
    screen->vtbl.store_derived_program_state(devinfo, cache_id, shader);
 
-   if (ish) {
-      simple_mtx_lock(&ish->lock);
+   util_queue_fence_signal(&shader->ready);
 
-      /* While unlikely, it's possible that another thread concurrently
-       * compiled the same variant.  Make sure no one beat us to it; if
-       * they did, return the existing one and discard our new one.
-       */
-      list_for_each_entry(struct iris_compiled_shader, existing,
-                          &ish->variants, link) {
-         if (memcmp(&existing->key, key, key_size) == 0) {
-            iris_delete_shader_variant(shader);
-            simple_mtx_unlock(&ish->lock);
-            return existing;
-         }
-      }
-
-      /* Append our new variant to the shader's variant list. */
-      list_addtail(&shader->link, &ish->variants);
-
-      simple_mtx_unlock(&ish->lock);
-   } else {
+   if (!ish) {
       struct keybox *keybox = make_keybox(shader, cache_id, key, key_size);
       _mesa_hash_table_insert(driver_shaders, keybox, shader);
    }
-
-   return shader;
 }
 
 bool



More information about the mesa-commit mailing list