radeonsi/gfx9: 2nd shader of merged shaders should hold a reference of the 1st
authorMarek Olšák <marek.olsak@amd.com>
Thu, 20 Apr 2017 11:06:31 +0000 (13:06 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Fri, 28 Apr 2017 19:47:35 +0000 (21:47 +0200)
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
src/gallium/drivers/radeonsi/si_shader.h
src/gallium/drivers/radeonsi/si_state_shaders.c

index f9ba79f56d66bcdb92ef7371d6c9310d03c42d4b..86bdb4fbe54a8f8007ac2e68870cbf5e3a2575e1 100644 (file)
@@ -493,6 +493,7 @@ struct si_shader {
        struct si_compiler_ctx_state    compiler_ctx_state;
 
        struct si_shader_selector       *selector;
+       struct si_shader_selector       *previous_stage_sel; /* for refcounting */
        struct si_shader                *next_variant;
 
        struct si_shader_part           *prolog;
index e5b72811c014025395940a876aea434393b3052b..546bb44e123b9365cfef8d4eda354f9777cd0f39 100644 (file)
@@ -1525,6 +1525,7 @@ static int si_shader_select_with_key(struct si_screen *sscreen,
                                     int thread_index)
 {
        struct si_shader_selector *sel = state->cso;
+       struct si_shader_selector *previous_stage_sel = NULL;
        struct si_shader *current = state->current;
        struct si_shader *iter, *shader = NULL;
 
@@ -1592,6 +1593,14 @@ again:
        shader->key = *key;
        shader->compiler_ctx_state = *compiler_state;
 
+       /* If this is a merged shader, get the first shader's selector. */
+       if (sscreen->b.chip_class >= GFX9) {
+               if (sel->type == PIPE_SHADER_TESS_CTRL)
+                       previous_stage_sel = key->part.tcs.ls;
+               else if (sel->type == PIPE_SHADER_GEOMETRY)
+                       previous_stage_sel = key->part.gs.es;
+       }
+
        /* Compile the main shader part if it doesn't exist. This can happen
         * if the initial guess was wrong. */
        bool is_pure_monolithic =
@@ -1608,22 +1617,18 @@ again:
                 * For merged shaders, check that the starting shader's main
                 * part is present.
                 */
-               if (sscreen->b.chip_class >= GFX9 &&
-                   (sel->type == PIPE_SHADER_TESS_CTRL ||
-                    sel->type == PIPE_SHADER_GEOMETRY)) {
-                       struct si_shader_selector *shader1 = NULL;
+               if (previous_stage_sel) {
                        struct si_shader_key shader1_key = zeroed;
 
-                       if (sel->type == PIPE_SHADER_TESS_CTRL) {
-                               shader1 = key->part.tcs.ls;
+                       if (sel->type == PIPE_SHADER_TESS_CTRL)
                                shader1_key.as_ls = 1;
-                       } else if (sel->type == PIPE_SHADER_GEOMETRY) {
-                               shader1 = key->part.gs.es;
+                       else if (sel->type == PIPE_SHADER_GEOMETRY)
                                shader1_key.as_es = 1;
-                       else
+                       else
                                assert(0);
 
-                       ok = si_check_missing_main_part(sscreen, shader1,
+                       ok = si_check_missing_main_part(sscreen,
+                                                       previous_stage_sel,
                                                        compiler_state, &shader1_key);
                } else {
                        ok = si_check_missing_main_part(sscreen, sel,
@@ -1636,6 +1641,15 @@ again:
                }
        }
 
+       /* Keep the reference to the 1st shader of merged shaders, so that
+        * Gallium can't destroy it before we destroy the 2nd shader.
+        *
+        * Set sctx = NULL, because it's unused if we're not releasing
+        * the shader, and we don't have any sctx here.
+        */
+       si_shader_selector_reference(NULL, &shader->previous_stage_sel,
+                                    previous_stage_sel);
+
        /* Monolithic-only shaders don't make a distinction between optimized
         * and unoptimized. */
        shader->is_monolithic =
@@ -2245,6 +2259,7 @@ static void si_delete_shader(struct si_context *sctx, struct si_shader *shader)
                }
        }
 
+       si_shader_selector_reference(sctx, &shader->previous_stage_sel, NULL);
        si_shader_destroy(shader);
        free(shader);
 }