zink: unspaghettify some program update code

the initial implementation of optimal_keys was added inline, but really
it's an entirely different codepath. by separating these out, it makes the
code more readable, and it also allows for slightly better optimization of
of the optimal_keys codepath

~4-5% improvement for drawoverhead -test 7

Reviewed-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18786>
This commit is contained in:
Mike Blumenkrantz
2022-09-06 12:35:43 -04:00
committed by Marge Bot
parent 809e9462ce
commit 7336580408
3 changed files with 88 additions and 43 deletions

View File

@@ -319,9 +319,13 @@ static bool
update_gfx_pipeline(struct zink_context *ctx, struct zink_batch_state *bs, enum pipe_prim_type mode)
{
VkPipeline prev_pipeline = ctx->gfx_pipeline_state.pipeline;
zink_gfx_program_update(ctx);
const struct zink_screen *screen = zink_screen(ctx->base.screen);
if (screen->optimal_keys)
zink_gfx_program_update_optimal(ctx);
else
zink_gfx_program_update(ctx);
VkPipeline pipeline;
if (zink_screen(ctx->base.screen)->info.have_EXT_graphics_pipeline_library)
if (screen->info.have_EXT_graphics_pipeline_library)
pipeline = zink_get_gfx_pipeline<DYNAMIC_STATE, true>(ctx, ctx->curr_program, &ctx->gfx_pipeline_state, mode);
else
pipeline = zink_get_gfx_pipeline<DYNAMIC_STATE, false>(ctx, ctx->curr_program, &ctx->gfx_pipeline_state, mode);

View File

@@ -548,15 +548,12 @@ update_gfx_program(struct zink_context *ctx, struct zink_gfx_program *prog)
void
zink_gfx_program_update(struct zink_context *ctx)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
if (ctx->last_vertex_stage_dirty) {
gl_shader_stage pstage = ctx->last_vertex_stage->nir->info.stage;
ctx->dirty_gfx_stages |= BITFIELD_BIT(pstage);
if (!screen->optimal_keys) {
memcpy(&ctx->gfx_pipeline_state.shader_keys.key[pstage].key.vs_base,
&ctx->gfx_pipeline_state.shader_keys.last_vertex.key.vs_base,
sizeof(struct zink_vs_key_base));
}
memcpy(&ctx->gfx_pipeline_state.shader_keys.key[pstage].key.vs_base,
&ctx->gfx_pipeline_state.shader_keys.last_vertex.key.vs_base,
sizeof(struct zink_vs_key_base));
ctx->last_vertex_stage_dirty = false;
}
if (ctx->gfx_dirty) {
@@ -568,37 +565,18 @@ zink_gfx_program_update(struct zink_context *ctx)
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ht, hash, ctx->gfx_stages);
if (entry) {
prog = (struct zink_gfx_program*)entry->data;
if (screen->optimal_keys) {
ctx->gfx_pipeline_state.optimal_key = ctx->gfx_pipeline_state.shader_keys_optimal.key.val;
if (ctx->gfx_pipeline_state.optimal_key != prog->last_variant_hash) {
const union zink_shader_key_optimal *optimal_key = (union zink_shader_key_optimal*)&prog->last_variant_hash;
uint8_t dirty = ctx->dirty_gfx_stages & prog->stages_present;
if (ctx->gfx_pipeline_state.shader_keys_optimal.key.vs_bits != optimal_key->vs_bits)
ctx->dirty_gfx_stages |= BITFIELD_BIT(ctx->last_vertex_stage->nir->info.stage);
if (ctx->gfx_pipeline_state.shader_keys_optimal.key.fs_bits != optimal_key->fs_bits)
ctx->dirty_gfx_stages |= BITFIELD_BIT(MESA_SHADER_FRAGMENT);
if (prog->shaders[MESA_SHADER_TESS_CTRL] && prog->shaders[MESA_SHADER_TESS_CTRL]->is_generated &&
ctx->gfx_pipeline_state.shader_keys_optimal.key.tcs_bits != optimal_key->tcs_bits)
ctx->dirty_gfx_stages |= BITFIELD_BIT(MESA_SHADER_TESS_CTRL);
update_gfx_shader_modules_optimal(ctx, screen, prog, dirty, &ctx->gfx_pipeline_state);
}
} else {
for (unsigned i = 0; i < ZINK_GFX_SHADER_COUNT; i++) {
if (prog->stages_present & ~ctx->dirty_gfx_stages & BITFIELD_BIT(i))
ctx->gfx_pipeline_state.modules[i] = prog->modules[i];
}
/* ensure variants are always updated if keys have changed since last use */
ctx->dirty_gfx_stages |= prog->stages_present;
update_gfx_program(ctx, prog);
for (unsigned i = 0; i < ZINK_GFX_SHADER_COUNT; i++) {
if (prog->stages_present & ~ctx->dirty_gfx_stages & BITFIELD_BIT(i))
ctx->gfx_pipeline_state.modules[i] = prog->modules[i];
}
/* ensure variants are always updated if keys have changed since last use */
ctx->dirty_gfx_stages |= prog->stages_present;
update_gfx_program(ctx, prog);
} else {
ctx->dirty_gfx_stages |= ctx->shader_stages;
prog = zink_create_gfx_program(ctx, ctx->gfx_stages, ctx->gfx_pipeline_state.dyn_state2.vertices_per_patch);
_mesa_hash_table_insert_pre_hashed(ht, hash, prog->shaders, prog);
if (screen->optimal_keys)
generate_gfx_program_modules_optimal(ctx, zink_screen(ctx->base.screen), prog, &ctx->gfx_pipeline_state);
else
generate_gfx_program_modules(ctx, zink_screen(ctx->base.screen), prog, &ctx->gfx_pipeline_state);
generate_gfx_program_modules(ctx, zink_screen(ctx->base.screen), prog, &ctx->gfx_pipeline_state);
}
simple_mtx_unlock(&ctx->program_lock[zink_program_cache_stages(ctx->shader_stages)]);
if (prog && prog != ctx->curr_program)
@@ -611,20 +589,82 @@ zink_gfx_program_update(struct zink_context *ctx)
} else if (ctx->dirty_gfx_stages) {
/* remove old hash */
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
if (screen->optimal_keys) {
if (ctx->gfx_pipeline_state.optimal_key != ctx->curr_program->last_variant_hash)
update_gfx_shader_modules_optimal(ctx, screen, ctx->curr_program,
ctx->dirty_gfx_stages & ctx->curr_program->stages_present,
&ctx->gfx_pipeline_state);
} else {
update_gfx_program(ctx, ctx->curr_program);
}
update_gfx_program(ctx, ctx->curr_program);
/* apply new hash */
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
}
ctx->dirty_gfx_stages = 0;
}
ALWAYS_INLINE static void
update_gfx_shader_module_optimal(struct zink_context *ctx, struct zink_gfx_program *prog, gl_shader_stage pstage)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
struct zink_shader_module *zm = get_shader_module_for_stage_optimal(ctx, screen, prog->shaders[pstage], prog, pstage, &ctx->gfx_pipeline_state);
if (!zm)
zm = create_shader_module_for_stage_optimal(ctx, screen, prog->shaders[pstage], prog, pstage, &ctx->gfx_pipeline_state);
prog->modules[pstage] = zm->shader;
}
static void
update_gfx_program_optimal(struct zink_context *ctx, struct zink_gfx_program *prog)
{
const union zink_shader_key_optimal *optimal_key = (union zink_shader_key_optimal*)&prog->last_variant_hash;
if (ctx->gfx_pipeline_state.shader_keys_optimal.key.vs_bits != optimal_key->vs_bits) {
update_gfx_shader_module_optimal(ctx, prog, ctx->last_vertex_stage->nir->info.stage);
ctx->gfx_pipeline_state.modules_changed = true;
}
if (ctx->gfx_pipeline_state.shader_keys_optimal.key.fs_bits != optimal_key->fs_bits) {
update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_FRAGMENT);
ctx->gfx_pipeline_state.modules_changed = true;
}
if (prog->shaders[MESA_SHADER_TESS_CTRL] && prog->shaders[MESA_SHADER_TESS_CTRL]->is_generated &&
ctx->gfx_pipeline_state.shader_keys_optimal.key.tcs_bits != optimal_key->tcs_bits) {
update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_TESS_CTRL);
ctx->gfx_pipeline_state.modules_changed = true;
}
prog->last_variant_hash = ctx->gfx_pipeline_state.shader_keys_optimal.key.val;
}
void
zink_gfx_program_update_optimal(struct zink_context *ctx)
{
if (ctx->gfx_dirty) {
struct zink_gfx_program *prog = NULL;
struct hash_table *ht = &ctx->program_cache[zink_program_cache_stages(ctx->shader_stages)];
const uint32_t hash = ctx->gfx_hash;
simple_mtx_lock(&ctx->program_lock[zink_program_cache_stages(ctx->shader_stages)]);
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ht, hash, ctx->gfx_stages);
if (ctx->curr_program)
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
if (entry) {
prog = (struct zink_gfx_program*)entry->data;
ctx->gfx_pipeline_state.optimal_key = ctx->gfx_pipeline_state.shader_keys_optimal.key.val;
update_gfx_program_optimal(ctx, prog);
} else {
ctx->dirty_gfx_stages |= ctx->shader_stages;
prog = zink_create_gfx_program(ctx, ctx->gfx_stages, ctx->gfx_pipeline_state.dyn_state2.vertices_per_patch);
_mesa_hash_table_insert_pre_hashed(ht, hash, prog->shaders, prog);
generate_gfx_program_modules_optimal(ctx, zink_screen(ctx->base.screen), prog, &ctx->gfx_pipeline_state);
}
simple_mtx_unlock(&ctx->program_lock[zink_program_cache_stages(ctx->shader_stages)]);
if (prog && prog != ctx->curr_program)
zink_batch_reference_program(&ctx->batch, &prog->base);
ctx->curr_program = prog;
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
} else if (ctx->dirty_gfx_stages) {
/* remove old hash */
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
update_gfx_program_optimal(ctx, ctx->curr_program);
/* apply new hash */
ctx->gfx_pipeline_state.final_hash ^= ctx->curr_program->last_variant_hash;
}
ctx->dirty_gfx_stages = 0;
ctx->gfx_dirty = false;
ctx->last_vertex_stage_dirty = false;
}
static void
update_cs_shader_module(struct zink_context *ctx, struct zink_compute_program *comp)
{

View File

@@ -120,7 +120,8 @@ zink_program_descriptor_is_buffer(struct zink_context *ctx, gl_shader_stage stag
void
zink_gfx_program_update(struct zink_context *ctx);
void
zink_gfx_program_update_optimal(struct zink_context *ctx);
uint32_t hash_gfx_output(const void *key);
uint32_t hash_gfx_input(const void *key);