From: Marek Olšák <marek.ol...@amd.com> --- src/gallium/drivers/radeonsi/si_shader.h | 1 + src/gallium/drivers/radeonsi/si_state_shaders.c | 35 ++++++++++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h index 514bb3c..5b665b5 100644 --- a/src/gallium/drivers/radeonsi/si_shader.h +++ b/src/gallium/drivers/radeonsi/si_shader.h @@ -498,20 +498,21 @@ struct si_shader_info { char face_vgpr_index; bool uses_instanceid; ubyte nr_pos_exports; ubyte nr_param_exports; }; 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; struct si_shader *previous_stage; /* for GFX9 */ struct si_shader_part *prolog2; struct si_shader_part *epilog; struct si_pm4_state *pm4; struct r600_resource *bo; struct r600_resource *scratch_bo; diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c index c5fa01d..94fc0e4 100644 --- a/src/gallium/drivers/radeonsi/si_state_shaders.c +++ b/src/gallium/drivers/radeonsi/si_state_shaders.c @@ -1517,20 +1517,21 @@ static void si_shader_selector_reference(struct si_context *sctx, } /* Select the hw shader variant depending on the current state. */ static int si_shader_select_with_key(struct si_screen *sscreen, struct si_shader_ctx_state *state, struct si_compiler_ctx_state *compiler_state, struct si_shader_key *key, 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; if (unlikely(sscreen->b.debug_flags & DBG_NO_OPT_VARIANT)) { memset(&key->opt, 0, sizeof(key->opt)); } again: /* Check if we don't need to change anything. * This path is also used for most shaders that don't need multiple @@ -1584,64 +1585,77 @@ again: /* Build a new shader. */ shader = CALLOC_STRUCT(si_shader); if (!shader) { mtx_unlock(&sel->mutex); return -ENOMEM; } shader->selector = sel; 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 = sscreen->use_monolithic_shaders || memcmp(&key->mono, &zeroed.mono, sizeof(key->mono)) != 0; if (!is_pure_monolithic) { bool ok; /* Make sure the main shader part is present. This is needed * for shaders that can be compiled as VS, LS, or ES, and only * one of them is compiled at creation. * * 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, compiler_state, key); } if (!ok) { FREE(shader); mtx_unlock(&sel->mutex); return -ENOMEM; /* skip the draw call */ } } + /* 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 = is_pure_monolithic || memcmp(&key->opt, &zeroed.opt, sizeof(key->opt)) != 0; shader->is_optimized = !is_pure_monolithic && memcmp(&key->opt, &zeroed.opt, sizeof(key->opt)) != 0; if (shader->is_optimized) @@ -2237,20 +2251,21 @@ static void si_delete_shader(struct si_context *sctx, struct si_shader *shader) si_pm4_delete_state(sctx, vs, shader->pm4); else si_pm4_delete_state(sctx, gs, shader->pm4); break; case PIPE_SHADER_FRAGMENT: si_pm4_delete_state(sctx, ps, shader->pm4); break; } } + si_shader_selector_reference(sctx, &shader->previous_stage_sel, NULL); si_shader_destroy(shader); free(shader); } static void si_destroy_shader_selector(struct si_context *sctx, struct si_shader_selector *sel) { struct si_shader *p = sel->first_variant, *c; struct si_shader_ctx_state *current_shader[SI_NUM_SHADERS] = { [PIPE_SHADER_VERTEX] = &sctx->vs_shader, -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev