From a0d4418de3e74bb36789d3e486db1f1483cc478f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 14 Jul 2025 00:55:28 +0200 Subject: [PATCH] etnaviv: update code steering bit when writing shader instructions When writing new shader instructions through the unified state area we must tell the GPU which caches to flush by setting the appropriate code steering bit. Failing to do this doesn't seem to have much of an effect when only loading shaders through the state memory, but when toggling between using icache (as in load shaders from memory) and loading instructions from the state area, this fixes severe corruption and GPU hangs due to old code being executed. Programming the steering bits is only needed for GPUs with either unified instruction or unified uniform states. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner Part-of: --- src/gallium/drivers/etnaviv/etnaviv_emit.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/gallium/drivers/etnaviv/etnaviv_emit.c b/src/gallium/drivers/etnaviv/etnaviv_emit.c index b7009e4a1eb..6b21dd8a78d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_emit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_emit.c @@ -636,7 +636,9 @@ etna_emit_state(struct etna_context *ctx) ETNA_DIRTY_SHADER | ETNA_DIRTY_CONSTBUF; /**** Large dynamically-sized state ****/ - bool do_uniform_flush = screen->info->halti < 5; + bool need_steering = screen->info->halti < 5 && + (screen->specs.has_unified_instmem || + screen->specs.has_unified_uniforms); if (dirty & (ETNA_DIRTY_SHADER)) { /* Special case: a new shader was loaded; simply re-load all uniforms and * shader code at once */ @@ -708,10 +710,14 @@ etna_emit_state(struct etna_context *ctx) ps_offset += ctx->shader_state.vs_inst_mem_size * 4; } + if (need_steering) + etna_set_state(stream, VIVS_SH_CONTROL, 0x0); etna_set_state_multi(stream, screen->specs.vs_offset, ctx->shader_state.vs_inst_mem_size, ctx->shader_state.VS_INST_MEM); + if (need_steering) + etna_set_state(stream, VIVS_SH_CONTROL, VIVS_SH_CONTROL_PS_CODE); etna_set_state_multi(stream, ps_offset, ctx->shader_state.ps_inst_mem_size, ctx->shader_state.PS_INST_MEM); @@ -722,12 +728,12 @@ etna_emit_state(struct etna_context *ctx) etna_set_state(stream, VIVS_PS_UNIFORM_BASE, ctx->shader.vs->uniforms.count / 4); } - if (do_uniform_flush) + if (need_steering) etna_set_state(stream, VIVS_SH_CONTROL, 0x0); etna_uniforms_write(ctx, ctx->shader.vs, ctx->constant_buffer[PIPE_SHADER_VERTEX].cb); - if (do_uniform_flush) + if (need_steering) etna_set_state(stream, VIVS_SH_CONTROL, VIVS_SH_CONTROL_PS_UNIFORM); etna_uniforms_write(ctx, ctx->shader.fs, ctx->constant_buffer[PIPE_SHADER_FRAGMENT].cb); @@ -740,14 +746,14 @@ etna_emit_state(struct etna_context *ctx) } } else { /* ideally this cache would only be flushed if there are VS uniform changes */ - if (do_uniform_flush) + if (need_steering) etna_set_state(stream, VIVS_SH_CONTROL, 0x0); if (dirty & (uniform_dirty_bits | ctx->shader.vs->uniforms_dirty_bits)) etna_uniforms_write(ctx, ctx->shader.vs, ctx->constant_buffer[PIPE_SHADER_VERTEX].cb); /* ideally this cache would only be flushed if there are PS uniform changes */ - if (do_uniform_flush) + if (need_steering) etna_set_state(stream, VIVS_SH_CONTROL, VIVS_SH_CONTROL_PS_UNIFORM); if (dirty & (uniform_dirty_bits | ctx->shader.fs->uniforms_dirty_bits))